@open-agent-toolkit/cli 0.1.41 → 0.1.42
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/agents/oat-phase-implementer.md +2 -2
- package/assets/agents/oat-reviewer.md +10 -8
- package/assets/docs/cli-utilities/workflow-gates.md +55 -0
- package/assets/docs/reference/cli-reference.md +1 -1
- package/assets/docs/workflows/projects/artifacts.md +22 -0
- package/assets/docs/workflows/projects/hill-checkpoints.md +2 -0
- package/assets/docs/workflows/projects/implementation-execution.md +2 -1
- package/assets/docs/workflows/projects/reviews.md +17 -0
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-project-implement/SKILL.md +76 -5
- package/assets/skills/oat-project-review-provide/SKILL.md +25 -13
- package/assets/skills/oat-project-review-receive/SKILL.md +20 -10
- package/assets/skills/oat-review-provide/SKILL.md +14 -12
- package/assets/skills/oat-review-provide/references/review-artifact-template.md +1 -1
- package/dist/commands/gate/index.d.ts.map +1 -1
- package/dist/commands/gate/index.js +15 -3
- package/dist/commands/review/latest.d.ts.map +1 -1
- package/dist/commands/review/latest.js +5 -2
- package/dist/commands/shared/frontmatter.d.ts +11 -0
- package/dist/commands/shared/frontmatter.d.ts.map +1 -1
- package/dist/commands/shared/frontmatter.js +15 -0
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-phase-implementer
|
|
3
|
-
version: 1.0.
|
|
3
|
+
version: 1.0.3
|
|
4
4
|
description: Implements a single plan phase end-to-end — reads artifacts once, executes tasks sequentially, commits per task, self-reviews, and returns a structured summary. Dispatched by oat-project-implement.
|
|
5
5
|
tools: Read, Write, Edit, Bash, Grep, Glob
|
|
6
6
|
color: cyan
|
|
@@ -46,7 +46,7 @@ For Codex, `provider-default` means the base/unpinned role follows Codex configu
|
|
|
46
46
|
|
|
47
47
|
If `mode: fix`, the block also includes:
|
|
48
48
|
|
|
49
|
-
- **review_artifact**: Path to the review artifact from the reviewer (e.g., `reviews/p02-review-
|
|
49
|
+
- **review_artifact**: Path to the review artifact from the reviewer (e.g., `reviews/p02-review-2026-01-28T140322Z.md`)
|
|
50
50
|
- **findings**: Critical and Important findings list
|
|
51
51
|
- **prior_summary**: Your own prior `implement` run summary (what was previously built)
|
|
52
52
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-reviewer
|
|
3
|
-
version: 1.1.
|
|
3
|
+
version: 1.1.4
|
|
4
4
|
description: Unified reviewer for OAT projects - mode-aware verification of requirements/design alignment and code quality. Writes a review artifact to disk by default, or returns structured findings in-memory when dispatched in structured-output mode.
|
|
5
5
|
tools: Read, Bash, Grep, Glob, Write
|
|
6
6
|
color: yellow
|
|
@@ -287,19 +287,21 @@ Write the review artifact to the specified path.
|
|
|
287
287
|
|
|
288
288
|
**File path format:**
|
|
289
289
|
|
|
290
|
-
-
|
|
291
|
-
- Final review: `{project}/reviews/final-review-YYYY-MM-DD.md`
|
|
292
|
-
- Task review: `{project}/reviews/pNN-tNN-review-YYYY-MM-DD.md`
|
|
293
|
-
- Range review: `{project}/reviews/range-review-YYYY-MM-DD.md`
|
|
290
|
+
Use a seconds-precision **UTC** timestamp token (`YYYY-MM-DDTHHMMSSZ`, from `date -u +%Y-%m-%dT%H%M%SZ` — the `-u` and the trailing `Z` are mandatory) so same-scope, same-day re-reviews never collide and always sort by recency. Never emit a local-time or `Z`-less timestamp: a timezone-less datetime mis-orders artifacts written by agents in different timezones.
|
|
294
291
|
|
|
295
|
-
|
|
292
|
+
- Phase review: `{project}/reviews/pNN-review-YYYY-MM-DDTHHMMSSZ.md`
|
|
293
|
+
- Final review: `{project}/reviews/final-review-YYYY-MM-DDTHHMMSSZ.md`
|
|
294
|
+
- Task review: `{project}/reviews/pNN-tNN-review-YYYY-MM-DDTHHMMSSZ.md`
|
|
295
|
+
- Range review: `{project}/reviews/range-review-YYYY-MM-DDTHHMMSSZ.md`
|
|
296
|
+
|
|
297
|
+
The timestamp token must match the `oat_generated_at` frontmatter for the same run. In the unlikely event a file with that exact second already exists, append `-v2`, `-v3`, etc.
|
|
296
298
|
|
|
297
299
|
**Review artifact template:**
|
|
298
300
|
|
|
299
301
|
````markdown
|
|
300
302
|
---
|
|
301
303
|
oat_generated: true
|
|
302
|
-
oat_generated_at: YYYY-MM-
|
|
304
|
+
oat_generated_at: YYYY-MM-DDTHH:MM:SSZ
|
|
303
305
|
oat_review_scope: { scope }
|
|
304
306
|
oat_review_type: { code|artifact|analysis }
|
|
305
307
|
oat_review_invocation: { manual|auto|gate }
|
|
@@ -308,7 +310,7 @@ oat_project: { project-path }
|
|
|
308
310
|
|
|
309
311
|
# {Code|Artifact|Analysis} Review: {scope}
|
|
310
312
|
|
|
311
|
-
**Reviewed:** YYYY-MM-
|
|
313
|
+
**Reviewed:** YYYY-MM-DDTHH:MM:SSZ
|
|
312
314
|
**Scope:** {scope description}
|
|
313
315
|
**Files reviewed:** {N}
|
|
314
316
|
**Commits:** {range or count}
|
|
@@ -71,6 +71,61 @@ status when the configured threshold is met. `cross-provider-exec` does not do
|
|
|
71
71
|
that interpretation; for generic prompts it still returns only the child process
|
|
72
72
|
status.
|
|
73
73
|
|
|
74
|
+
`oat-project-implement` uses `oat gate review` per phase when a project opts in
|
|
75
|
+
via the `oat_phase_review_gate` plan frontmatter — a non-pausing gate that runs
|
|
76
|
+
after each selected phase's standard reviewer passes. See
|
|
77
|
+
[Reviews → Phase review gate](../workflows/projects/reviews.md#phase-review-gate)
|
|
78
|
+
for the frontmatter contract and how passing versus blocking gates are
|
|
79
|
+
dispositioned.
|
|
80
|
+
|
|
81
|
+
### Gate completion signal
|
|
82
|
+
|
|
83
|
+
The canonical "how do I know the gate finished" signal is the structured result
|
|
84
|
+
`oat --json gate review` writes to stdout on exit, together with the process
|
|
85
|
+
exit code. Orchestrators should run the gate synchronously and read that
|
|
86
|
+
envelope — do **not** poll the `reviews/` directory for a file to appear or
|
|
87
|
+
watch the provider process's log for liveness. Filesystem and log-liveness
|
|
88
|
+
heuristics are unreliable: a re-gate can momentarily surface a prior round's
|
|
89
|
+
artifact, and a lingering provider side-process says nothing about whether the
|
|
90
|
+
review committed.
|
|
91
|
+
|
|
92
|
+
Every terminal envelope carries a `runId` (unique per gate invocation) and,
|
|
93
|
+
once an artifact exists, its `generatedAt` (the artifact's seconds-precision
|
|
94
|
+
`oat_generated_at`), so a caller can correlate the result to the exact artifact
|
|
95
|
+
and disambiguate re-gate rounds:
|
|
96
|
+
|
|
97
|
+
| `status` | Exit | Meaning |
|
|
98
|
+
| ---------------------------- | ---- | --------------------------------------------------------- |
|
|
99
|
+
| `ok` | 0 | Review completed; gate passed at the threshold. |
|
|
100
|
+
| `blocked` | 1 | Review completed; findings at/above the threshold. |
|
|
101
|
+
| `review_failed` | ≠0 | The provider target exited non-zero; no verdict. |
|
|
102
|
+
| `artifact_validation_failed` | 1 | Provider ran but the review artifact could not be parsed. |
|
|
103
|
+
|
|
104
|
+
`ok` and `blocked` also include `outcome`, `artifactPath`, `counts`, `scope`,
|
|
105
|
+
and `handoff`. Treat any status other than `ok`/`blocked` as an operational
|
|
106
|
+
failure, not a passing gate.
|
|
107
|
+
|
|
108
|
+
**Drive gates through `oat gate review`, not raw provider invocation.** An
|
|
109
|
+
orchestrator that hand-rolls the review (for example, calling
|
|
110
|
+
`codex exec … oat-project-review-provide <scope>` directly) and then watches
|
|
111
|
+
`reviews/` for a file is reimplementing — less reliably — what the CLI already
|
|
112
|
+
does: `oat gate review` snapshots the reviews directory, dispatches the
|
|
113
|
+
provider, and attributes the produced artifact by content hash, so it is immune
|
|
114
|
+
to a stale file lingering from a prior round. It works standalone, not only
|
|
115
|
+
inside the `oat-project-implement` auto-loop — a one-off final review is just:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
oat --json gate review \
|
|
119
|
+
--project "$PROJECT_PATH" \
|
|
120
|
+
--review-type code \
|
|
121
|
+
--review-scope final \
|
|
122
|
+
--exit-nonzero-on important \
|
|
123
|
+
'Use oat-project-review-provide code final to review the current project'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Read the resulting envelope and exit code; that is the whole completion
|
|
127
|
+
contract.
|
|
128
|
+
|
|
74
129
|
## Exec targets
|
|
75
130
|
|
|
76
131
|
`oat gate cross-provider-exec` chooses from `workflow.gates.execTargets`.
|
|
@@ -68,7 +68,7 @@ Notable commands introduced in the current CLI surface:
|
|
|
68
68
|
- `oat repo archive sync [project-name]` - hydrate archived project snapshots from the configured repo-scoped S3 archive into `.oat/projects/archived/`. The old `oat project archive sync` path remains as a deprecated shim.
|
|
69
69
|
- `oat project validate-plan --project-path <path>` - validates `oat_plan_parallel_groups` metadata in `plan.md`; exits non-zero on invalid. See [Implementation Execution](../workflows/projects/implementation-execution.md#validating-plan-metadata).
|
|
70
70
|
- `oat project set-mode` — deprecated no-op. Execution mode is no longer user-selectable; emits a deprecation warning and preserves the `--json` contract.
|
|
71
|
-
- `oat gate review <prompt...>` - run a stateful OAT review through the target registry, parse the produced review artifact, and exit nonzero for configured blocking findings; produced gate reviews use `oat_review_invocation: gate` and still require `oat-project-review-receive` handoff before they are dispositioned.
|
|
71
|
+
- `oat gate review <prompt...>` - run a stateful OAT review through the target registry, parse the produced review artifact, and exit nonzero for configured blocking findings; produced gate reviews use `oat_review_invocation: gate` and still require `oat-project-review-receive` handoff before they are dispositioned. With `--json`, the result envelope on exit is the canonical completion signal — `status` (`ok` | `blocked` | `review_failed` | `artifact_validation_failed`), `runId`, `generatedAt`, `artifactPath` — so orchestrators should read it rather than poll the filesystem. Runs standalone (e.g. `--review-scope final`), not only inside `oat-project-implement`. See [Workflow Gates → Gate completion signal](../cli-utilities/workflow-gates.md#gate-completion-signal).
|
|
72
72
|
- `oat gate cross-provider-exec <prompt...>` - choose an available exec target while avoiding the current runtime by default, then run the prompt with the chosen target's configured base command and exit with the child status.
|
|
73
73
|
|
|
74
74
|
## `oat config` surface flags
|
|
@@ -57,6 +57,7 @@ See [Project Splitting](splitting.md) for the full parent/child model.
|
|
|
57
57
|
|
|
58
58
|
- `oat_plan_hill_phases` — list of phase IDs to pause at for HiLL checkpoints.
|
|
59
59
|
- `oat_plan_parallel_groups` — declares which phases may execute concurrently in worktrees. See below.
|
|
60
|
+
- `oat_phase_review_gate` — opt-in non-pausing external review gate that runs after a phase's standard reviewer passes. See below.
|
|
60
61
|
|
|
61
62
|
#### oat_plan_parallel_groups
|
|
62
63
|
|
|
@@ -85,6 +86,27 @@ Each inner array is a group of phases that execute concurrently in their own wor
|
|
|
85
86
|
|
|
86
87
|
Before dispatching, `oat-project-implement` invokes `oat project validate-plan --project-path "${PROJECT_PATH}"`. Non-zero exit blocks the run. See [CLI Reference](../../reference/cli-reference.md) and [Implementation Execution](implementation-execution.md) for details.
|
|
87
88
|
|
|
89
|
+
#### oat_phase_review_gate
|
|
90
|
+
|
|
91
|
+
Enable an optional, non-pausing external review gate that runs after each selected phase's standard reviewer passes and its bookkeeping is committed:
|
|
92
|
+
|
|
93
|
+
```yaml
|
|
94
|
+
oat_phase_review_gate:
|
|
95
|
+
enabled: true
|
|
96
|
+
phases: [] # empty or omitted = every implementation phase
|
|
97
|
+
review_type: code
|
|
98
|
+
exit_nonzero_on: important
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Semantics:**
|
|
102
|
+
|
|
103
|
+
- Missing, `null`, or `enabled: false` → disabled (default). `enabled: true` activates the gate.
|
|
104
|
+
- `phases` → optional. Empty or missing runs the gate after every implementation phase; a populated list restricts it to those phase IDs, each of which must exist in the plan body.
|
|
105
|
+
- `review_type` → optional, defaults to `code`. Only `code` is supported for phase gates.
|
|
106
|
+
- `exit_nonzero_on` → optional, defaults to `important`. One of `critical`, `important`, `medium`, `minor`. This is the blocking threshold: findings at or above it stop the phase; sub-threshold findings are dispositioned by the judgment sweep rather than ignored.
|
|
107
|
+
|
|
108
|
+
A malformed gate stops the run before task execution rather than being silently disabled. The gate is independent of HiLL checkpoints and reuses the existing `oat gate review` target config — it does not hardcode a `--target`. See [Reviews → Phase review gate](reviews.md#phase-review-gate) for the runtime behavior and disposition rules.
|
|
109
|
+
|
|
88
110
|
## Reference artifacts
|
|
89
111
|
|
|
90
112
|
- `.oat/templates/*.md`
|
|
@@ -10,6 +10,8 @@ OAT supports two checkpoint classes:
|
|
|
10
10
|
- Workflow phase checkpoints
|
|
11
11
|
- Plan phase checkpoints
|
|
12
12
|
|
|
13
|
+
The [phase review gate](reviews.md#phase-review-gate) (`oat_phase_review_gate`) is a separate, non-pausing mechanism — it does not pause on a passing gate and never modifies the HiLL keys below (`oat_hill_completed`, `oat_plan_hill_phases`).
|
|
14
|
+
|
|
13
15
|
## Workflow checkpoints (`state.md`)
|
|
14
16
|
|
|
15
17
|
Frontmatter keys:
|
|
@@ -187,7 +187,8 @@ For each phase in the plan (whether sequential or inside a parallel group):
|
|
|
187
187
|
5. **Parse the verdict:** zero Critical + zero Important findings → `pass`; otherwise `fail`.
|
|
188
188
|
6. **On fail, run the bounded fix loop** (see below).
|
|
189
189
|
7. **Update artifacts** (`implementation.md`, `plan.md` review row, `state.md`) and make the mandatory bookkeeping commit.
|
|
190
|
-
8. **
|
|
190
|
+
8. **Phase review gate** — when `oat_phase_review_gate` selects the phase, run the optional non-pausing external gate (`oat gate review`) after the step 7 bookkeeping commit and before the HiLL check. A passing gate continues automatically; a blocking gate is received and fixed, reusing the bounded fix loop's `oat_orchestration_retry_limit`. See [Reviews → Phase review gate](reviews.md#phase-review-gate).
|
|
191
|
+
9. **HiLL checkpoint** if the phase id is listed in `oat_plan_hill_phases`.
|
|
191
192
|
|
|
192
193
|
### Bounded fix loop
|
|
193
194
|
|
|
@@ -107,6 +107,23 @@ Auto-triggered reviews use `oat_review_invocation: auto` in the review artifact
|
|
|
107
107
|
|
|
108
108
|
This feature is opt-in and disabled by default. When disabled, the manual `oat-project-review-provide` workflow applies.
|
|
109
109
|
|
|
110
|
+
## Phase review gate
|
|
111
|
+
|
|
112
|
+
The phase review gate is an optional, **non-pausing** external review gate that runs after a phase's standard per-phase reviewer passes and the phase bookkeeping is committed. Where the Tier 1 reviewer is an in-session self-review, the gate calls `oat gate review` against the configured cross-provider target, adding an independent perspective before implementation moves to the next phase. It is enabled per-project through `plan.md` frontmatter (`oat_phase_review_gate`; see [Project Artifacts](artifacts.md#oat_phase_review_gate) for the field shape and validation).
|
|
113
|
+
|
|
114
|
+
It is independent of [HiLL checkpoints](hill-checkpoints.md): a passing gate does not pause, and the gate never touches `oat_hill_completed`, `oat_plan_hill_phases`, or `oat_auto_review_at_hill_checkpoints`.
|
|
115
|
+
|
|
116
|
+
Gate-produced review artifacts use `oat_review_invocation: gate` in frontmatter (the third invocation marker alongside `manual` and `auto`). The gate verdict — controlled by `exit_nonzero_on` (default `important`) — decides whether the **phase stops**; it does not decide whether sub-threshold findings are ignored. Either way the produced artifact is consumed by `oat-project-review-receive`, autonomously and without user prompts, so findings never evaporate:
|
|
117
|
+
|
|
118
|
+
- **Passing gate** (no findings at or above the threshold): receive runs a non-pausing **judgment sweep**. It makes a per-finding decision for each Medium/Minor — defer to final review (the default, recorded so [final review](#phase-and-final-review) resurfaces it), address now (only for small, contained, low-risk fixes, which do **not** re-trigger the standard reviewer or re-gate the phase), or reject with rationale — then archives the artifact. Address-now is an exception, not the norm; if such a fix reveals a Critical/Important concern it escalates to the blocking path.
|
|
119
|
+
- **Blocking gate** (one or more findings at or above the threshold): receive converts findings to fix tasks and implementation re-runs the standard reviewer and the gate for the phase. These block → fix → re-gate rounds are bounded by `oat_orchestration_retry_limit` (default `2`); exhausting the bound stops a sequential run or excludes the phase in a parallel group, matching the standard fix loop's terminal handling.
|
|
120
|
+
|
|
121
|
+
Gate-originated artifacts (`oat_review_invocation: gate`) are excluded from the same-scope review-cycle cap in `oat-project-review-receive`. The cap measures failed fix cycles of the standard review loop, so counting gate artifacts would trip it on artifact volume rather than real fix rounds.
|
|
122
|
+
|
|
123
|
+
When a phase is re-gated multiple times, each round produces a distinct review artifact — filenames and `oat_generated_at` are seconds-precision, so rounds never collide and `oat review latest` resolves the newest. An orchestrator should know a gate finished from the `oat --json gate review` result envelope on process exit (`status`, `runId`, `generatedAt`), not by watching the `reviews/` directory or the provider's log; see [Gate completion signal](../../cli-utilities/workflow-gates.md#gate-completion-signal).
|
|
124
|
+
|
|
125
|
+
This feature is opt-in and disabled by default (missing or `enabled: false`). For a parallel phase group, selected gates run after fan-in and bookkeeping, one per merged phase in plan order.
|
|
126
|
+
|
|
110
127
|
## Auto artifact-review loops
|
|
111
128
|
|
|
112
129
|
Generated planning and analysis artifacts have a separate review loop from code/phase reviews.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-implement
|
|
3
|
-
version: 2.0.
|
|
3
|
+
version: 2.0.25
|
|
4
4
|
description: Use when plan.md is ready for execution. Dispatches phase-level subagents with bounded fix loops; supports plan-declared parallel phase groups with worktree-isolated execution and ordered fan-in.
|
|
5
5
|
oat_gateable: true
|
|
6
6
|
argument-hint: '[--retry-limit <N>] [--dry-run]'
|
|
@@ -679,6 +679,39 @@ This setting controls only the extra `oat-project-review-provide` lifecycle revi
|
|
|
679
679
|
|
|
680
680
|
**On resume:** If `oat_auto_review_at_hill_checkpoints` is already present in plan.md frontmatter, skip Touchpoint A entirely — do not re-ask, do not re-read config, do not print the auto-review note. The stored value is authoritative. If only legacy `oat_auto_review_at_checkpoints` is present, treat it as authoritative for this run and write the new `oat_auto_review_at_hill_checkpoints` key on the next plan frontmatter update.
|
|
681
681
|
|
|
682
|
+
### Step 2.6: Validate Optional Phase Review Gate
|
|
683
|
+
|
|
684
|
+
Read `oat_phase_review_gate` from `"$PROJECT_PATH/plan.md"` frontmatter when present.
|
|
685
|
+
|
|
686
|
+
This is the plan-level `phaseReviewGate` setting: an optional, non-pausing external lifecycle review gate that runs after a phase's standard per-phase self-review passes. It uses the existing `oat gate review` target configuration to run a cross-provider review, then maps the produced review artifact to a blocking/non-blocking gate result.
|
|
687
|
+
|
|
688
|
+
Valid shape:
|
|
689
|
+
|
|
690
|
+
```yaml
|
|
691
|
+
oat_phase_review_gate:
|
|
692
|
+
enabled: true
|
|
693
|
+
phases: [] # empty or omitted = every implementation phase
|
|
694
|
+
review_type: code
|
|
695
|
+
exit_nonzero_on: important
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
Validation rules:
|
|
699
|
+
|
|
700
|
+
- Missing, `null`, or `enabled: false` means disabled.
|
|
701
|
+
- `enabled: true` activates the gate.
|
|
702
|
+
- `phases` is optional. If missing or empty (`[]`), run after every implementation phase. If populated, every value must be a known plan phase ID.
|
|
703
|
+
- `review_type` is optional and defaults to `code`. This skill only supports `code` phase gates; any other value is invalid for implementation phase execution.
|
|
704
|
+
- `exit_nonzero_on` is optional and defaults to `important`. Allowed values: `critical`, `important`, `medium`, `minor`.
|
|
705
|
+
|
|
706
|
+
If the setting is invalid, stop before task execution and ask the user to repair `plan.md`. Do not silently disable a malformed gate.
|
|
707
|
+
|
|
708
|
+
This setting is independent from HiLL checkpoints:
|
|
709
|
+
|
|
710
|
+
- It does not pause when the gate passes.
|
|
711
|
+
- It does not append to `oat_hill_completed`.
|
|
712
|
+
- It does not alter `oat_plan_hill_phases` or `oat_auto_review_at_hill_checkpoints`.
|
|
713
|
+
- It uses the existing gate target config; do not hardcode `--target` in reusable plan execution unless the user explicitly asks for manual/debug routing.
|
|
714
|
+
|
|
682
715
|
### Step 3: Check Implementation State
|
|
683
716
|
|
|
684
717
|
Check if implementation already started:
|
|
@@ -892,6 +925,43 @@ On reviewer verdict `fail`, run a bounded fix loop.
|
|
|
892
925
|
- **Sequential mode:** STOP the run. Surface to user with phase ID, unresolved findings, review artifact path. Do not proceed to subsequent phases.
|
|
893
926
|
- **Parallel group mode:** mark the phase `excluded`. Do not merge its worktree. Continue the remaining phases in the group. Report in Outstanding Items after the group completes.
|
|
894
927
|
|
|
928
|
+
### Optional External Phase Review Gate
|
|
929
|
+
|
|
930
|
+
After the standard per-phase reviewer passes and after the required phase bookkeeping commit is cleanly recorded, check `oat_phase_review_gate`.
|
|
931
|
+
|
|
932
|
+
If the gate is enabled and the current phase is selected:
|
|
933
|
+
|
|
934
|
+
1. Run the gate from the orchestration branch with the active project path:
|
|
935
|
+
|
|
936
|
+
```bash
|
|
937
|
+
oat --json gate review \
|
|
938
|
+
--project "$PROJECT_PATH" \
|
|
939
|
+
--review-type code \
|
|
940
|
+
--review-scope "{pNN}" \
|
|
941
|
+
--exit-nonzero-on "{threshold}" \
|
|
942
|
+
'$oat-project-review-provide code {pNN}'
|
|
943
|
+
```
|
|
944
|
+
|
|
945
|
+
- `{threshold}` comes from `oat_phase_review_gate.exit_nonzero_on` (default: `important`).
|
|
946
|
+
- `{pNN}` is the completed phase ID.
|
|
947
|
+
- Do not pass `--target` in normal execution; the existing gate config selects the cross-provider target.
|
|
948
|
+
- The gate CLI injects gate context into the review prompt. The produced review artifact must use `oat_review_invocation: gate`.
|
|
949
|
+
|
|
950
|
+
2. Parse the JSON result. The gate verdict (`exit_nonzero_on: {threshold}`) decides whether the phase **stops**; it does not decide whether sub-threshold findings are ignored. Either way the produced artifact must be **consumed** — passing gate artifacts are not left unprocessed at the top level of `reviews/`.
|
|
951
|
+
- `status: "ok"` / exit code `0` means the phase gate passed at the configured threshold, so the phase does not stop. Still run `oat-project-review-receive` for the reported artifact path in non-pausing **judgment-sweep** mode (pass gate-passed context so receive selects sweep disposition). The sweep makes a per-finding judgment for each Medium/Minor — defer to final (default), address now (small/contained/low-risk fixes only), or reject with rationale — writes those durable dispositions into `implementation.md`, and archives the artifact. Then continue without pausing. Address-now fixes from a passing gate do **not** re-trigger the standard reviewer or re-gate the phase.
|
|
952
|
+
- `status: "blocked"` / non-zero exit due to review findings means blocking findings exist. Run `oat-project-review-receive` for the reported artifact path (blocking disposition) before treating the gate review as consumed.
|
|
953
|
+
- A non-zero exit caused by target execution failure, artifact validation failure, or missing review artifact is an operational failure. Stop and surface the gate output; do not continue as if the gate passed.
|
|
954
|
+
|
|
955
|
+
3. If `oat-project-review-receive` adds fix tasks (blocking gate, or a sweep address-now fix that revealed a Critical/Important concern):
|
|
956
|
+
- Return to task execution for the newly added review-fix tasks.
|
|
957
|
+
- After fixes land, re-run the standard per-phase reviewer and this external phase gate for the same phase.
|
|
958
|
+
- Continue only after both the standard reviewer and the external phase gate pass.
|
|
959
|
+
- Bound these gate block → fix → re-gate rounds by `oat_orchestration_retry_limit` (from `state.md`, default `2`). If the limit is exhausted with the gate still blocking, apply the same terminal handling as the standard bounded fix loop: **sequential mode** stops the run and surfaces the phase ID, unresolved findings, and artifact path; **parallel group mode** marks the phase `excluded` and reports it in Outstanding Items.
|
|
960
|
+
|
|
961
|
+
4. If the judgment sweep (passing gate) records only deferrals/rejections and no blocking fix tasks, record the receive result and continue.
|
|
962
|
+
|
|
963
|
+
For a parallel group, run selected phase gates after fan-in and bookkeeping, one gate per successfully merged phase in plan order. If a phase gate blocks, stop the schedule and process that gate's review before starting later schedule entries.
|
|
964
|
+
|
|
895
965
|
### Parallel Group Execution
|
|
896
966
|
|
|
897
967
|
When the current schedule entry is a multi-phase group, execute as follows.
|
|
@@ -966,7 +1036,7 @@ When the current schedule entry is a multi-phase group, execute as follows.
|
|
|
966
1036
|
|
|
967
1037
|
For phases that were excluded (fix-loop exhausted), preserve the worktree and log its path in `implementation.md` Outstanding Items.
|
|
968
1038
|
|
|
969
|
-
8. **Bookkeeping commit** after the group completes. Then HiLL checkpoint check.
|
|
1039
|
+
8. **Bookkeeping commit** after the group completes. Then run any selected external phase review gates. After those gates pass, perform the HiLL checkpoint check.
|
|
970
1040
|
|
|
971
1041
|
### Step 7: Artifact Updates After Each Phase (or Group)
|
|
972
1042
|
|
|
@@ -1039,7 +1109,7 @@ git add {PROJECT_PATH}/implementation.md {PROJECT_PATH}/state.md {PROJECT_PATH}/
|
|
|
1039
1109
|
git commit -m "chore(oat): bookkeeping after {pNN} {pass|fail}"
|
|
1040
1110
|
```
|
|
1041
1111
|
|
|
1042
|
-
Then check HiLL checkpoint — if the phase ID is in `oat_plan_hill_phases`, pause for user approval before continuing.
|
|
1112
|
+
Then run the optional external phase review gate for the completed phase when `oat_phase_review_gate` selects it. After the gate passes or is skipped, check HiLL checkpoint — if the phase ID is in `oat_plan_hill_phases`, pause for user approval before continuing.
|
|
1043
1113
|
|
|
1044
1114
|
### Step 8: Check Plan Phase Completion
|
|
1045
1115
|
|
|
@@ -1130,6 +1200,7 @@ Do not use `git add -A` or glob patterns. Only commit the three project artifact
|
|
|
1130
1200
|
|
|
1131
1201
|
- **Workflow HiLL** (`oat_hill_checkpoints` in state.md): Gates between workflow phases (discovery → spec → design → plan → implement). Checked by oat-project-progress router.
|
|
1132
1202
|
- **Plan phase checkpoints** (`oat_plan_hill_phases` in plan.md): Gates at plan phase boundaries during implementation. `[]` means pause after every phase; a populated array pauses only after listed phases. The field may be absent only before the first implementation-run confirmation. Listed phases are where you stop AFTER completing them.
|
|
1203
|
+
- **Phase review gate** (`oat_phase_review_gate` in plan.md): Optional non-pausing external review gate after a completed phase passes the standard reviewer. Missing/disabled means skip; `phases: []` means gate every implementation phase. Passing gates continue automatically; blocking gates are received/fixed before execution proceeds.
|
|
1133
1204
|
|
|
1134
1205
|
**Revision phase completion handling:**
|
|
1135
1206
|
|
|
@@ -1296,7 +1367,7 @@ echo "$FINAL_ROW"
|
|
|
1296
1367
|
**If final review row exists and status is `passed`:**
|
|
1297
1368
|
|
|
1298
1369
|
- Example row:
|
|
1299
|
-
- `| final | code | passed | 2026-01-28 | reviews/final-review-2026-01-
|
|
1370
|
+
- `| final | code | passed | 2026-01-28 | reviews/final-review-2026-01-28T140322Z.md |`
|
|
1300
1371
|
- Check:
|
|
1301
1372
|
```bash
|
|
1302
1373
|
echo "$FINAL_ROW" | grep -qE "^\\|\\s*final\\s*\\|.*\\|\\s*passed\\s*\\|" && echo "passed"
|
|
@@ -1446,7 +1517,7 @@ Final verification:
|
|
|
1446
1517
|
|
|
1447
1518
|
Final review:
|
|
1448
1519
|
- Status: ✓ passed
|
|
1449
|
-
- Artifact: reviews/final-review-{
|
|
1520
|
+
- Artifact: reviews/final-review-{timestamp}.md
|
|
1450
1521
|
|
|
1451
1522
|
Next: Create PR or run the oat-project-pr-final skill (when available)
|
|
1452
1523
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-review-provide
|
|
3
|
-
version: 1.3.
|
|
3
|
+
version: 1.3.10
|
|
4
4
|
description: Use when the user explicitly asks to review an OAT project — e.g. "review project", "review the project", "run project review", or confirms a previously offered review. Do NOT auto-invoke on completed work alone. Resolves a project review scope and offers before running.
|
|
5
5
|
disable-model-invocation: false
|
|
6
6
|
user-invocable: true
|
|
@@ -25,11 +25,13 @@ Reviewers should distinguish implementation defects from artifact drift. If code
|
|
|
25
25
|
|
|
26
26
|
## Model Invocation Gate
|
|
27
27
|
|
|
28
|
-
This skill is model-invokable only for explicit review asks such as "review project" or "review the project", or when the user confirms a previously offered project-review step. Do NOT auto-invoke merely because a task, phase, or implementation appears complete.
|
|
28
|
+
This skill is model-invokable only for explicit review asks such as "review project" or "review the project", or when the user confirms a previously offered project-review step. A gate-originated request from `oat gate review` is also an explicit review ask. Do NOT auto-invoke merely because a task, phase, or implementation appears complete.
|
|
29
29
|
|
|
30
30
|
Before acting, verify that there is an active OAT project or a user-provided review target that can be resolved to project state. If neither exists, do not run this skill; offer `oat-project-open` / `oat-project-quick-start` for project workflow setup, or `oat-review-provide` for a non-project ad-hoc review.
|
|
31
31
|
|
|
32
|
-
When the
|
|
32
|
+
When the invocation is manual, summarize the inferred review type and scope, then ask before running the review.
|
|
33
|
+
|
|
34
|
+
**Gate-originated mode:** If the request context says the review is gate-originated, set `REVIEW_INVOCATION=gate`, honor any provided review type/scope arguments, and run without interactive confirmation prompts. The gate session is already the explicit authorization boundary. If subagent dispatch is unavailable, run the review inline in the current gate session instead of handing off to a fresh session.
|
|
33
35
|
|
|
34
36
|
## Mode Assertion
|
|
35
37
|
|
|
@@ -123,7 +125,7 @@ Tell user:
|
|
|
123
125
|
- `oat-project-quick-start` (new quick project)
|
|
124
126
|
- `oat-project-import-plan` (external plan import)
|
|
125
127
|
|
|
126
|
-
If validation passes, derive `{project-name}` as basename of `PROJECT_PATH`. Summarize the resolved project/review target
|
|
128
|
+
If validation passes, derive `{project-name}` as basename of `PROJECT_PATH`. Summarize the resolved project/review target. For manual invocation, ask before continuing to Step 1. For `REVIEW_INVOCATION=gate`, continue without asking.
|
|
127
129
|
|
|
128
130
|
### Step 1: Parse Arguments or Ask
|
|
129
131
|
|
|
@@ -424,6 +426,8 @@ Files changed: {FILE_COUNT}
|
|
|
424
426
|
Proceed with review?
|
|
425
427
|
```
|
|
426
428
|
|
|
429
|
+
If `REVIEW_INVOCATION=gate`, print the same scope summary but do not ask `Proceed with review?`; continue directly.
|
|
430
|
+
|
|
427
431
|
### Step 4.1: Dispatch Profile Override Advisory (Artifact Plan Only)
|
|
428
432
|
|
|
429
433
|
When reviewing `artifact plan`, apply this Dispatch Profile override advisory:
|
|
@@ -536,6 +540,7 @@ Detection logic:
|
|
|
536
540
|
- If the runtime can dispatch reviewer work (`subagent_type` in Claude Code, Cursor invocation via `/name` or natural mention, or Codex multi-agent spawn/auto-spawn) → **Tier 1**.
|
|
537
541
|
- If the Task tool is not available or subagent dispatch is not supported → **Tier 2**.
|
|
538
542
|
- If user explicitly requests inline or confirms they are already in a fresh session → **Tier 3**.
|
|
543
|
+
- If `REVIEW_INVOCATION=gate` and Tier 1 is unavailable, skip Tier 2 and use **Tier 3** inline. Do not return fresh-session instructions from a gate invocation.
|
|
539
544
|
|
|
540
545
|
**Step 6b: Tier 1 — Subagent (if available)**
|
|
541
546
|
|
|
@@ -566,6 +571,7 @@ If subagent not available:
|
|
|
566
571
|
- If user is already in a fresh session (confirmed), proceed to Tier 3.
|
|
567
572
|
- If Codex reported `authorization required` and the user approved delegation, do **not** use Tier 2. Return to Tier 1 and delegate to `oat-reviewer`.
|
|
568
573
|
- If user prefers fresh session: provide instructions and exit.
|
|
574
|
+
- If `REVIEW_INVOCATION=gate`: do not provide fresh-session instructions; run Tier 3 inline instead.
|
|
569
575
|
|
|
570
576
|
Instructions for fresh session:
|
|
571
577
|
|
|
@@ -599,13 +605,15 @@ Review storage contract:
|
|
|
599
605
|
|
|
600
606
|
**Naming convention:**
|
|
601
607
|
|
|
602
|
-
-
|
|
603
|
-
|
|
604
|
-
-
|
|
605
|
-
-
|
|
606
|
-
-
|
|
608
|
+
Use a seconds-precision **UTC** timestamp token (`YYYY-MM-DDTHHMMSSZ`, from `date -u +%Y-%m-%dT%H%M%SZ` — the `-u` and the trailing `Z` are mandatory), not a date-only or local-time stamp, so that same-scope re-reviews and re-gates within one day never collide and `oat review latest` orders them by recency:
|
|
609
|
+
|
|
610
|
+
- Phase review: `{PROJECT_PATH}/reviews/pNN-review-YYYY-MM-DDTHHMMSSZ.md`
|
|
611
|
+
- Task review: `{PROJECT_PATH}/reviews/pNN-tNN-review-YYYY-MM-DDTHHMMSSZ.md`
|
|
612
|
+
- Final review: `{PROJECT_PATH}/reviews/final-review-YYYY-MM-DDTHHMMSSZ.md`
|
|
613
|
+
- Range review: `{PROJECT_PATH}/reviews/range-review-YYYY-MM-DDTHHMMSSZ.md`
|
|
614
|
+
- Artifact review: `{PROJECT_PATH}/reviews/artifact-{artifact}-review-YYYY-MM-DDTHHMMSSZ.md`
|
|
607
615
|
|
|
608
|
-
|
|
616
|
+
Set `oat_generated_at` in the artifact frontmatter to the matching full timestamp (`YYYY-MM-DDTHH:MM:SSZ`). Same-second collisions are effectively impossible for sequential runs; if one occurs, append `-v2`, `-v3`, etc.
|
|
609
617
|
|
|
610
618
|
**Important:** `PROJECT_PATH` here must be the resolved path from Step 1.5. If a worktree was detected, this path is relative to the worktree root, ensuring the artifact is written on the correct branch.
|
|
611
619
|
|
|
@@ -636,7 +644,7 @@ Shared ad-hoc companion reference (non-project mode):
|
|
|
636
644
|
```markdown
|
|
637
645
|
---
|
|
638
646
|
oat_generated: true
|
|
639
|
-
oat_generated_at: {
|
|
647
|
+
oat_generated_at: { full UTC timestamp, e.g. 2026-07-06T11:16:01Z }
|
|
640
648
|
oat_review_scope: { scope }
|
|
641
649
|
oat_review_type: { code|artifact }
|
|
642
650
|
oat_review_invocation: { manual|auto|gate }
|
|
@@ -655,9 +663,13 @@ oat_project: { PROJECT_PATH }
|
|
|
655
663
|
|
|
656
664
|
- `manual` (default): Review was manually triggered by the user. `oat-project-review-receive` uses standard disposition behavior (user prompts for triage, minors auto-deferred for non-final scopes).
|
|
657
665
|
- `auto`: Review was spawned by the auto-review checkpoint trigger in `oat-project-implement`. `oat-project-review-receive` uses relaxed disposition: minors are auto-converted to fix tasks (not deferred), no user prompts for disposition decisions.
|
|
658
|
-
- `gate`: Review was spawned by `oat gate review
|
|
666
|
+
- `gate`: Review was spawned by `oat gate review` for a workflow gate. Gate-originated reviews use normal stateful review-provide behavior: write the review artifact, update the `## Reviews` row, and commit review bookkeeping. The gate CLI maps the review artifact findings to exit status, and `oat-project-review-receive` dispositions gate reviews autonomously (no user prompts) — selecting convert-to-fix-tasks when the gate **blocked** at its threshold, or non-pausing judgment-sweep disposition (defer / small-fix-now / reject, with sub-threshold findings recorded durably) when the gate **passed**.
|
|
667
|
+
|
|
668
|
+
When `oat-project-implement` spawns this skill for auto-review at checkpoints, it passes context indicating auto invocation. Set `oat_review_invocation: auto` in the artifact frontmatter.
|
|
669
|
+
|
|
670
|
+
When `oat gate review` invokes this skill, it includes gate-originated context instructing the reviewer to write `oat_review_invocation: gate`. Honor that instruction in the artifact frontmatter.
|
|
659
671
|
|
|
660
|
-
|
|
672
|
+
For all other invocations (user-triggered, fresh session), use `manual`.
|
|
661
673
|
|
|
662
674
|
Gate parsing contract:
|
|
663
675
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-review-receive
|
|
3
|
-
version: 1.5.
|
|
3
|
+
version: 1.5.6
|
|
4
4
|
description: Use when the user explicitly asks to receive review findings for an OAT project — e.g. "receive review", "process review", "process the project review", or confirms a previously offered review-receive step. Do NOT auto-invoke merely because a review file exists. Resolves the latest review and offers before acting.
|
|
5
5
|
disable-model-invocation: false
|
|
6
6
|
user-invocable: true
|
|
@@ -102,7 +102,7 @@ fi
|
|
|
102
102
|
|
|
103
103
|
Selection rules:
|
|
104
104
|
|
|
105
|
-
- Use `oat review latest` as the first-choice resolver. It scans project reviews (`reviews/` and `reviews/archived/`) plus ad-hoc review locations and orders candidates by `oat_generated_at` frontmatter rather than filesystem mtime.
|
|
105
|
+
- Use `oat review latest` as the first-choice resolver. It scans project reviews (`reviews/` and `reviews/archived/`) plus ad-hoc review locations and orders candidates by `oat_generated_at` frontmatter rather than filesystem mtime. Review artifacts carry a seconds-precision `oat_generated_at` and a matching timestamped filename, so same-scope same-day re-gates order deterministically and the newest round wins — never assume the plain `<scope>-review-<date>.md` name is current.
|
|
106
106
|
- Read the JSON result:
|
|
107
107
|
- `path: null` means no review target was found.
|
|
108
108
|
- `kind: "project"` and `actionable: true` means this skill can process the target when the path is an active top-level project review.
|
|
@@ -267,15 +267,23 @@ Read `oat_review_type` and `oat_review_invocation` from review artifact frontmat
|
|
|
267
267
|
- Require explicit user confirmation before applying any artifact edits.
|
|
268
268
|
- Resolve findings directly in artifact files; do not convert findings into plan tasks.
|
|
269
269
|
- Do not defer findings by default. Only use `rejected_with_rationale` for invalid findings, or `needs_user_direction` when user input is required.
|
|
270
|
-
- If `oat_review_type == code` AND `oat_review_invocation == auto
|
|
271
|
-
- **Auto-disposition mode.** This review was spawned by the auto-review checkpoint trigger in `oat-project-implement`. Apply relaxed disposition defaults:
|
|
270
|
+
- If `oat_review_type == code` AND `oat_review_invocation == auto`, OR `oat_review_invocation == gate` from a **blocking** gate (the gate-originated context does not indicate a passing-gate sweep):
|
|
271
|
+
- **Auto-disposition mode.** This review was spawned by the auto-review checkpoint trigger in `oat-project-implement` or by a blocking `oat gate review`. Apply relaxed disposition defaults:
|
|
272
272
|
- Critical/Important/Medium: convert to fix tasks (same as manual mode)
|
|
273
|
-
- Minor: auto-convert to fix tasks unless clearly out of scope (e.g., cosmetic polish unrelated to changed code). Manual mode now also defaults minors to `convert` (see Step 9); auto mode keeps the same intent — fix everything while context is fresh — but without any user prompts.
|
|
274
|
-
- **No user prompts for disposition decisions.** The auto
|
|
273
|
+
- Minor: auto-convert to fix tasks unless clearly out of scope (e.g., cosmetic polish unrelated to changed code). Manual mode now also defaults minors to `convert` (see Step 9); auto/gate mode keeps the same intent — fix everything while context is fresh — but without any user prompts.
|
|
274
|
+
- **No user prompts for disposition decisions.** The auto/gate review path runs fully autonomously.
|
|
275
275
|
- Genuinely ambiguous findings (e.g., a medium the agent disagrees with) are deferred with a note explaining why, rather than pausing for interactive resolution.
|
|
276
276
|
- Follow the task-conversion flow in Steps 3-10 with these adjusted defaults.
|
|
277
|
-
- If `oat_review_type == code` AND `oat_review_invocation == gate
|
|
278
|
-
- **
|
|
277
|
+
- If `oat_review_type == code` AND `oat_review_invocation == gate` from a **passing** gate (the gate-originated context indicates a passing-gate judgment sweep):
|
|
278
|
+
- **Judgment-sweep mode.** The phase gate already passed at its `exit_nonzero_on` threshold, so the phase does not stop. Consume the artifact anyway, so its sub-threshold findings become durable, ordered dispositions in `implementation.md` instead of evaporating. Fully non-pausing; no user prompts.
|
|
279
|
+
- The gate verdict decided whether the phase stops; it did **not** decide whether Medium/Minor findings are ignored. There are, by definition, no unresolved Critical/Important findings in a passing gate (if there were, the gate would have blocked).
|
|
280
|
+
- Make a per-finding **judgment call** for each Medium/Minor — do not mechanically dump them all:
|
|
281
|
+
- **Defer to final** (default): record under "Deferred Findings" (Mediums under "Deferred Findings (Medium)" so Step 8.5 resurfacing picks them up) with concrete rationale.
|
|
282
|
+
- **Address now:** only for small, contained, low-risk fixes. Apply the fix, commit it with the phase bookkeeping, and record the disposition. Do **not** re-run the standard reviewer or re-gate the phase for address-now fixes.
|
|
283
|
+
- **Reject** as false-positive / out-of-scope, with concrete rationale.
|
|
284
|
+
- `address now` is an **exception, not the norm** — when in doubt, defer. Do not let a passing gate drift into behaving like a Medium-blocking gate by habit.
|
|
285
|
+
- **Escalation exception:** if an address-now fix reveals or creates a Critical/Important concern, stop treating it as a sweep item. Convert it to a fix task and return control to the blocking-gate path (`oat-project-implement` re-runs the standard reviewer and the gate for the phase).
|
|
286
|
+
- Do not add blocking fix tasks for deferred or rejected findings. After recording all dispositions, archive the artifact (Step 7.5) and commit review bookkeeping (Step 7.6) as usual.
|
|
279
287
|
- If `oat_review_type == code` (manual or `oat_review_invocation` absent):
|
|
280
288
|
- Follow the existing task-conversion flow in Steps 3-10 with standard disposition behavior.
|
|
281
289
|
|
|
@@ -483,13 +491,15 @@ If the project itself is still untracked because earlier lifecycle steps never c
|
|
|
483
491
|
|
|
484
492
|
**Bounded loop protection:**
|
|
485
493
|
|
|
486
|
-
Count how many review cycles have occurred for this scope:
|
|
494
|
+
Count how many review cycles have occurred for this scope. Exclude gate-originated artifacts (`oat_review_invocation: gate`): the cap measures failed fix cycles of the standard review loop, not artifact volume, and phase gate re-runs are governed by the phase review gate flow in `oat-project-implement`, not by this cap.
|
|
487
495
|
|
|
488
496
|
```bash
|
|
489
497
|
{
|
|
490
498
|
find "$PROJECT_PATH/reviews" -maxdepth 1 -type f -name "*$SCOPE_TOKEN*.md" 2>/dev/null
|
|
491
499
|
find "$PROJECT_PATH/reviews/archived" -maxdepth 1 -type f -name "*$SCOPE_TOKEN*.md" 2>/dev/null
|
|
492
|
-
} |
|
|
500
|
+
} | while IFS= read -r artifact; do
|
|
501
|
+
grep -q "oat_review_invocation: gate" "$artifact" || echo "$artifact"
|
|
502
|
+
done | wc -l
|
|
493
503
|
```
|
|
494
504
|
|
|
495
505
|
**If 3 or more cycles:**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-review-provide
|
|
3
|
-
version: 1.2.
|
|
3
|
+
version: 1.2.3
|
|
4
4
|
description: Use when you need an ad-hoc review outside an active OAT project lifecycle. Reviews code or artifacts without project phase state, unlike oat-project-review-provide.
|
|
5
5
|
argument-hint: '[unstaged|staged|base_branch=<branch>|base_sha=<sha>|<sha1>..<sha2>|--files <path1,path2,...>] [--output <path>] [--mode auto|local|tracked|inline]'
|
|
6
6
|
disable-model-invocation: true
|
|
@@ -151,18 +151,20 @@ If user asks for tracked `.oat/repo/reviews` and it is gitignored, warn and ask
|
|
|
151
151
|
|
|
152
152
|
Derive a **scope slug** from the resolved scope mode so that the filename indicates what was reviewed:
|
|
153
153
|
|
|
154
|
-
| Scope mode | Slug derivation | Example filename
|
|
155
|
-
| ---------------------- | ------------------------------------ |
|
|
156
|
-
| `base_branch=<branch>` | Current branch name | `ad-hoc-review-2026-02-
|
|
157
|
-
| `unstaged` | Literal `unstaged` | `ad-hoc-review-2026-02-
|
|
158
|
-
| `staged` | Literal `staged` | `ad-hoc-review-2026-02-
|
|
159
|
-
| `--files <paths>` | First 2–3 basenames, joined with `-` | `ad-hoc-review-2026-02-
|
|
160
|
-
| `base_sha=<sha>` | Short SHA (7 chars) | `ad-hoc-review-2026-02-
|
|
161
|
-
| `<sha1>..<sha2>` | Both short SHAs joined with `-` | `ad-hoc-review-2026-02-
|
|
154
|
+
| Scope mode | Slug derivation | Example filename |
|
|
155
|
+
| ---------------------- | ------------------------------------ | ----------------------------------------------------- |
|
|
156
|
+
| `base_branch=<branch>` | Current branch name | `ad-hoc-review-2026-02-16T140322Z-oat-repo.md` |
|
|
157
|
+
| `unstaged` | Literal `unstaged` | `ad-hoc-review-2026-02-16T140322Z-unstaged.md` |
|
|
158
|
+
| `staged` | Literal `staged` | `ad-hoc-review-2026-02-16T140322Z-staged.md` |
|
|
159
|
+
| `--files <paths>` | First 2–3 basenames, joined with `-` | `ad-hoc-review-2026-02-16T140322Z-auth-login.md` |
|
|
160
|
+
| `base_sha=<sha>` | Short SHA (7 chars) | `ad-hoc-review-2026-02-16T140322Z-abc1234.md` |
|
|
161
|
+
| `<sha1>..<sha2>` | Both short SHAs joined with `-` | `ad-hoc-review-2026-02-16T140322Z-abc1234-def5678.md` |
|
|
162
162
|
|
|
163
163
|
```bash
|
|
164
164
|
mkdir -p "$OUTPUT_DIR"
|
|
165
|
-
|
|
165
|
+
# Seconds-precision UTC token so same-scope same-day re-reviews never collide and
|
|
166
|
+
# order by recency in `oat review latest`. The trailing Z (UTC) is mandatory.
|
|
167
|
+
STAMP=$(date -u +%Y-%m-%dT%H%M%SZ)
|
|
166
168
|
|
|
167
169
|
# Derive SCOPE_SLUG based on scope mode (examples):
|
|
168
170
|
# base_branch → SCOPE_SLUG=$(git branch --show-current | tr '/' '-')
|
|
@@ -174,10 +176,10 @@ TODAY=$(date +%Y-%m-%d)
|
|
|
174
176
|
# Sanitize: lowercase, replace non-alphanumeric with '-', collapse runs, trim to 40 chars
|
|
175
177
|
SCOPE_SLUG=$(echo "$SCOPE_SLUG" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g; s/--*/-/g; s/^-//; s/-$//' | cut -c1-40)
|
|
176
178
|
|
|
177
|
-
OUT_FILE="$OUTPUT_DIR/ad-hoc-review-${
|
|
179
|
+
OUT_FILE="$OUTPUT_DIR/ad-hoc-review-${STAMP}-${SCOPE_SLUG}.md"
|
|
178
180
|
```
|
|
179
181
|
|
|
180
|
-
|
|
182
|
+
Set `oat_generated_at` in the artifact frontmatter to the matching full UTC timestamp (`YYYY-MM-DDTHH:MM:SSZ`). Same-second collisions are effectively impossible for sequential runs; if one occurs, suffix with `-v2`, `-v3`, etc.
|
|
181
183
|
|
|
182
184
|
### Step 4: Run Review
|
|
183
185
|
|
|
@@ -5,7 +5,7 @@ Use this template for non-project commit-range reviews.
|
|
|
5
5
|
````markdown
|
|
6
6
|
---
|
|
7
7
|
oat_generated: true
|
|
8
|
-
oat_generated_at: YYYY-MM-
|
|
8
|
+
oat_generated_at: YYYY-MM-DDTHH:MM:SSZ
|
|
9
9
|
oat_review_type: code
|
|
10
10
|
oat_review_scope: { scope }
|
|
11
11
|
oat_review_scope_mode: { files|unstaged|staged|range }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/gate/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/gate/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EAQL,KAAK,UAAU,EAIf,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,UAAU,EAEhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,UAAU,uBAAuB;IAC/B,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,KACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,UAAU,EAAE,CACV,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,iBAAiB,KACvB,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AA0CD,UAAU,iBAAiB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,OAAO,EAAE,gBAAgB,GAAG,cAAc,GAAG,SAAS,CAAC;IACvD,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC7B;AAED,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,kBAAkB,GAAG,cAAc,GAAG,MAAM,CAAC;AAMlD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,CAAC;CACpB;AAyZD,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,EAC9C,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,kBAAkB,GACxB,kBAAkB,GAAG,IAAI,CAE3B;AAu7BD,wBAAgB,iBAAiB,CAC/B,SAAS,GAAE,OAAO,CAAC,uBAAuB,CAAM,GAC/C,OAAO,CAwKT"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import { createHash } from 'node:crypto';
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
3
|
import { readdir, readFile } from 'node:fs/promises';
|
|
4
4
|
import { basename, isAbsolute, join, relative } from 'node:path';
|
|
5
5
|
import { buildCommandContext, } from '../../app/command-context.js';
|
|
6
|
-
import { getFrontmatterBlock, getFrontmatterField, } from '../shared/frontmatter.js';
|
|
6
|
+
import { getFrontmatterBlock, getFrontmatterField, parseGeneratedTime, } from '../shared/frontmatter.js';
|
|
7
7
|
import { readGlobalOptions } from '../shared/shared.utils.js';
|
|
8
8
|
import { BUILTIN_EXEC_TARGETS, readOatConfig, readOatLocalConfig, readUserConfig, writeOatConfig, writeOatLocalConfig, writeUserConfig, } from '../../config/oat-config.js';
|
|
9
9
|
import { resolveEffectiveConfig, resolveExecTargets, resolveGate, } from '../../config/resolve.js';
|
|
@@ -502,7 +502,7 @@ async function readReviewGateArtifactCandidate(repoRoot, relativePath) {
|
|
|
502
502
|
if (!generatedAt) {
|
|
503
503
|
return null;
|
|
504
504
|
}
|
|
505
|
-
const generatedTime =
|
|
505
|
+
const generatedTime = parseGeneratedTime(generatedAt);
|
|
506
506
|
if (Number.isNaN(generatedTime)) {
|
|
507
507
|
return null;
|
|
508
508
|
}
|
|
@@ -616,6 +616,7 @@ function writeReviewGateResult(context, payload) {
|
|
|
616
616
|
else {
|
|
617
617
|
context.logger.info('Review completed and gate passed.');
|
|
618
618
|
}
|
|
619
|
+
context.logger.info(`Run: ${payload.runId} (generated ${payload.generatedAt})`);
|
|
619
620
|
context.logger.info(`Review artifact: ${payload.artifactPath}`);
|
|
620
621
|
if (payload.normalization) {
|
|
621
622
|
context.logger.info(`Artifact normalized: inserted ${payload.normalization.insertedSeverities.map((severity) => severityDisplayName(severity)).join(', ')} empty Findings section(s).`);
|
|
@@ -629,6 +630,7 @@ function writeReviewGateExecutionFailure(context, payload) {
|
|
|
629
630
|
context.logger.json({
|
|
630
631
|
status: 'review_failed',
|
|
631
632
|
outcome: 'review_did_not_complete',
|
|
633
|
+
runId: payload.runId,
|
|
632
634
|
target: payload.target,
|
|
633
635
|
project: payload.project,
|
|
634
636
|
exitCode: payload.exitCode,
|
|
@@ -643,9 +645,11 @@ function writeReviewGateArtifactValidationFailure(context, payload) {
|
|
|
643
645
|
context.logger.json({
|
|
644
646
|
status: 'artifact_validation_failed',
|
|
645
647
|
outcome: 'review_completed_artifact_validation_failed',
|
|
648
|
+
runId: payload.runId,
|
|
646
649
|
target: payload.target,
|
|
647
650
|
project: payload.project,
|
|
648
651
|
artifactPath: payload.artifactPath,
|
|
652
|
+
generatedAt: payload.generatedAt,
|
|
649
653
|
message: payload.message,
|
|
650
654
|
recovery: payload.recovery,
|
|
651
655
|
});
|
|
@@ -755,6 +759,7 @@ async function runCrossProviderExec(prompt, options, context, dependencies) {
|
|
|
755
759
|
}
|
|
756
760
|
}
|
|
757
761
|
async function runReviewGate(prompt, options, context, dependencies) {
|
|
762
|
+
const runId = randomUUID();
|
|
758
763
|
try {
|
|
759
764
|
const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
760
765
|
const userConfigDir = join(context.home, '.oat');
|
|
@@ -785,6 +790,7 @@ async function runReviewGate(prompt, options, context, dependencies) {
|
|
|
785
790
|
const childExitCode = await executeTarget(selected, [reviewPrompt], context, dependencies);
|
|
786
791
|
if (childExitCode !== 0) {
|
|
787
792
|
writeReviewGateExecutionFailure(context, {
|
|
793
|
+
runId,
|
|
788
794
|
target: selected.id,
|
|
789
795
|
project: projectPath,
|
|
790
796
|
exitCode: childExitCode,
|
|
@@ -799,9 +805,11 @@ async function runReviewGate(prompt, options, context, dependencies) {
|
|
|
799
805
|
const producedArtifact = findProducedReviewArtifact(before, after);
|
|
800
806
|
if (!producedArtifact) {
|
|
801
807
|
writeReviewGateArtifactValidationFailure(context, {
|
|
808
|
+
runId,
|
|
802
809
|
target: selected.id,
|
|
803
810
|
project: projectPath,
|
|
804
811
|
artifactPath: null,
|
|
812
|
+
generatedAt: null,
|
|
805
813
|
message: `No new review artifact was detected for project ${projectPath}.`,
|
|
806
814
|
recovery: 'Ensure the review provider wrote a project review artifact. If it did, fix or attach that artifact and run oat-project-review-receive before treating the review as consumed.',
|
|
807
815
|
});
|
|
@@ -817,9 +825,11 @@ async function runReviewGate(prompt, options, context, dependencies) {
|
|
|
817
825
|
catch (error) {
|
|
818
826
|
const detail = error instanceof Error ? error.message : String(error);
|
|
819
827
|
writeReviewGateArtifactValidationFailure(context, {
|
|
828
|
+
runId,
|
|
820
829
|
target: selected.id,
|
|
821
830
|
project: projectPath,
|
|
822
831
|
artifactPath: producedArtifact.path,
|
|
832
|
+
generatedAt: producedArtifact.generatedAt,
|
|
823
833
|
message: detail,
|
|
824
834
|
recovery: `The review artifact was created at ${producedArtifact.path} but could not be consumed. Fix the artifact format, then run oat-project-review-receive for ${producedArtifact.path}; if the only issue is a missing zero-count severity heading, rerun the gate to normalize the same artifact instead of creating a new review version.`,
|
|
825
835
|
});
|
|
@@ -835,9 +845,11 @@ async function runReviewGate(prompt, options, context, dependencies) {
|
|
|
835
845
|
});
|
|
836
846
|
writeReviewGateResult(context, {
|
|
837
847
|
status: blocking ? 'blocked' : 'ok',
|
|
848
|
+
runId,
|
|
838
849
|
target: selected.id,
|
|
839
850
|
project: projectPath,
|
|
840
851
|
artifactPath: producedArtifact.path,
|
|
852
|
+
generatedAt: producedArtifact.generatedAt,
|
|
841
853
|
threshold,
|
|
842
854
|
blocking,
|
|
843
855
|
counts: verdict.counts,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"latest.d.ts","sourceRoot":"","sources":["../../../src/commands/review/latest.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"latest.d.ts","sourceRoot":"","sources":["../../../src/commands/review/latest.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAO9B,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE7E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,OAAO,CAAC;AAEnD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,gBAAgB,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;CACrB;AAQD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,UAAU,wBAAwB;IAChC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;CACnE;AAsID,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAqF9B;AA+CD,wBAAgB,yBAAyB,CACvC,SAAS,GAAE,OAAO,CAAC,wBAAwB,CAAM,GAChD,OAAO,CAkBT"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readdir, readFile } from 'node:fs/promises';
|
|
2
2
|
import { isAbsolute, join, relative } from 'node:path';
|
|
3
3
|
import { buildCommandContext, } from '../../app/command-context.js';
|
|
4
|
-
import { getFrontmatterBlock, getFrontmatterField, } from '../shared/frontmatter.js';
|
|
4
|
+
import { getFrontmatterBlock, getFrontmatterField, parseGeneratedTime, } from '../shared/frontmatter.js';
|
|
5
5
|
import { readGlobalOptions } from '../shared/shared.utils.js';
|
|
6
6
|
import { readOatLocalConfig } from '../../config/oat-config.js';
|
|
7
7
|
import { normalizeToPosixPath, resolveProjectRoot } from '../../fs/paths.js';
|
|
@@ -72,7 +72,7 @@ async function readReviewCandidate(repoRoot, relativePath, kind, priority, archi
|
|
|
72
72
|
if (!generatedAt) {
|
|
73
73
|
return null;
|
|
74
74
|
}
|
|
75
|
-
const generatedTime =
|
|
75
|
+
const generatedTime = parseGeneratedTime(generatedAt);
|
|
76
76
|
if (Number.isNaN(generatedTime)) {
|
|
77
77
|
return null;
|
|
78
78
|
}
|
|
@@ -99,6 +99,9 @@ function sortReviewCandidates(a, b) {
|
|
|
99
99
|
if (a.lifecycleRank !== b.lifecycleRank) {
|
|
100
100
|
return b.lifecycleRank - a.lifecycleRank;
|
|
101
101
|
}
|
|
102
|
+
// Same scope, same generated time: fall back to a stable path order. Review
|
|
103
|
+
// artifacts carry a seconds-precision `oat_generated_at`, so distinct re-gate
|
|
104
|
+
// rounds differ on generatedTime above and never reach this branch.
|
|
102
105
|
return a.path.localeCompare(b.path);
|
|
103
106
|
}
|
|
104
107
|
export async function findLatestReview(options) {
|
|
@@ -9,6 +9,17 @@ export declare function isProjectStatePhase(value: string): value is ProjectStat
|
|
|
9
9
|
export declare function isProjectStateFrontmatterField(value: string): value is ProjectStateFrontmatterField;
|
|
10
10
|
export declare function getFrontmatterBlock(content: string): string | null;
|
|
11
11
|
export declare function getFrontmatterField(frontmatter: string, field: string): string | null;
|
|
12
|
+
/**
|
|
13
|
+
* Parse an `oat_generated_at` value into a comparable epoch millisecond time.
|
|
14
|
+
*
|
|
15
|
+
* Review artifacts should carry a UTC, `Z`-suffixed timestamp
|
|
16
|
+
* (`YYYY-MM-DDTHH:MM:SSZ`). A bare date (`YYYY-MM-DD`) already parses as UTC,
|
|
17
|
+
* but a datetime with no timezone designator parses as *local* time, which
|
|
18
|
+
* mis-orders artifacts written by agents in different timezones. Treat such a
|
|
19
|
+
* value as UTC by appending `Z` so ordering is timezone-independent regardless
|
|
20
|
+
* of what the writer emitted. Returns `NaN` for unparseable input.
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseGeneratedTime(value: string): number;
|
|
12
23
|
export declare function parseFrontmatterField(filePath: string, field: string): Promise<string>;
|
|
13
24
|
export declare function getSkillVersion(skillDir: string): Promise<string | null>;
|
|
14
25
|
export declare function getAgentVersion(agentPath: string): Promise<string | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../../src/commands/shared/frontmatter.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB,6CAA8C,CAAC;AAE/E,eAAO,MAAM,oBAAoB,gFAOvB,CAAC;AAEX,eAAO,MAAM,gCAAgC,sgBA2BnC,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AACpE,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AACtE,MAAM,MAAM,4BAA4B,GACtC,CAAC,OAAO,gCAAgC,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,gBAAgB,CAE3E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,iBAAiB,CAE7E;AAED,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,MAAM,GACZ,KAAK,IAAI,4BAA4B,CAIvC;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGlE;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,MAAM,GAAG,IAAI,CAKf;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CASjB;AAED,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQxB;AAED,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGxB"}
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../../src/commands/shared/frontmatter.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB,6CAA8C,CAAC;AAE/E,eAAO,MAAM,oBAAoB,gFAOvB,CAAC;AAEX,eAAO,MAAM,gCAAgC,sgBA2BnC,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AACpE,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AACtE,MAAM,MAAM,4BAA4B,GACtC,CAAC,OAAO,gCAAgC,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,gBAAgB,CAE3E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,iBAAiB,CAE7E;AAED,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,MAAM,GACZ,KAAK,IAAI,4BAA4B,CAIvC;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGlE;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,MAAM,GAAG,IAAI,CAKf;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIxD;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CASjB;AAED,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQxB;AAED,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGxB"}
|
|
@@ -57,6 +57,21 @@ export function getFrontmatterField(frontmatter, field) {
|
|
|
57
57
|
return null;
|
|
58
58
|
return match[1].replace(/\s*#.*$/, '').trim();
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Parse an `oat_generated_at` value into a comparable epoch millisecond time.
|
|
62
|
+
*
|
|
63
|
+
* Review artifacts should carry a UTC, `Z`-suffixed timestamp
|
|
64
|
+
* (`YYYY-MM-DDTHH:MM:SSZ`). A bare date (`YYYY-MM-DD`) already parses as UTC,
|
|
65
|
+
* but a datetime with no timezone designator parses as *local* time, which
|
|
66
|
+
* mis-orders artifacts written by agents in different timezones. Treat such a
|
|
67
|
+
* value as UTC by appending `Z` so ordering is timezone-independent regardless
|
|
68
|
+
* of what the writer emitted. Returns `NaN` for unparseable input.
|
|
69
|
+
*/
|
|
70
|
+
export function parseGeneratedTime(value) {
|
|
71
|
+
const hasTime = value.includes('T');
|
|
72
|
+
const hasZone = /(?:[zZ]|[+-]\d{2}:?\d{2})$/.test(value);
|
|
73
|
+
return Date.parse(hasTime && !hasZone ? `${value}Z` : value);
|
|
74
|
+
}
|
|
60
75
|
export async function parseFrontmatterField(filePath, field) {
|
|
61
76
|
try {
|
|
62
77
|
const content = await readFile(filePath, 'utf8');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-agent-toolkit/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.42",
|
|
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",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"ora": "^9.0.0",
|
|
35
35
|
"yaml": "2.8.2",
|
|
36
36
|
"zod": "^3.25.76",
|
|
37
|
-
"@open-agent-toolkit/control-plane": "0.1.
|
|
37
|
+
"@open-agent-toolkit/control-plane": "0.1.42"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^22.10.0",
|