@open-agent-toolkit/cli 0.1.5 → 0.1.7
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-reviewer.md +10 -1
- package/assets/docs/workflows/projects/artifacts.md +17 -0
- package/assets/docs/workflows/projects/index.md +3 -0
- package/assets/docs/workflows/projects/splitting.md +79 -0
- package/assets/docs/workflows/skills/index.md +2 -0
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-brainstorm/SKILL.md +43 -3
- package/assets/skills/oat-project-discover/SKILL.md +72 -8
- package/assets/skills/oat-project-implement/SKILL.md +21 -1
- package/assets/skills/oat-project-quick-start/SKILL.md +14 -5
- package/assets/skills/oat-project-review-provide/SKILL.md +9 -1
- package/assets/skills/oat-project-review-receive/SKILL.md +21 -1
- package/assets/skills/oat-project-split/SKILL.md +82 -0
- package/assets/skills/oat-project-summary/SKILL.md +15 -13
- package/assets/templates/implementation.md +5 -5
- package/assets/templates/state.md +6 -1
- package/assets/templates/summary.md +2 -1
- package/dist/__tests__/skills/split-flow-fixtures.d.ts +50 -0
- package/dist/__tests__/skills/split-flow-fixtures.d.ts.map +1 -0
- package/dist/__tests__/skills/split-flow-fixtures.js +161 -0
- package/dist/commands/init/tools/shared/skill-manifest.d.ts +1 -1
- package/dist/commands/init/tools/shared/skill-manifest.d.ts.map +1 -1
- package/dist/commands/init/tools/shared/skill-manifest.js +1 -0
- package/dist/commands/project/complete-discovery/index.d.ts +16 -0
- package/dist/commands/project/complete-discovery/index.d.ts.map +1 -0
- package/dist/commands/project/complete-discovery/index.js +123 -0
- package/dist/commands/project/complete-state/index.d.ts.map +1 -1
- package/dist/commands/project/complete-state/index.js +5 -0
- package/dist/commands/project/index.d.ts.map +1 -1
- package/dist/commands/project/index.js +4 -0
- package/dist/commands/project/list.d.ts +6 -0
- package/dist/commands/project/list.d.ts.map +1 -1
- package/dist/commands/project/list.js +37 -4
- package/dist/commands/project/new/scaffold.d.ts.map +1 -1
- package/dist/commands/project/new/scaffold.js +4 -0
- package/dist/commands/project/open/index.d.ts.map +1 -1
- package/dist/commands/project/open/index.js +9 -3
- package/dist/commands/project/pause/index.d.ts.map +1 -1
- package/dist/commands/project/pause/index.js +7 -1
- package/dist/commands/project/split/evaluate-signals.d.ts +8 -0
- package/dist/commands/project/split/evaluate-signals.d.ts.map +1 -0
- package/dist/commands/project/split/evaluate-signals.js +47 -0
- package/dist/commands/project/split/index.d.ts +3 -0
- package/dist/commands/project/split/index.d.ts.map +1 -0
- package/dist/commands/project/split/index.js +11 -0
- package/dist/commands/project/split/run.d.ts +21 -0
- package/dist/commands/project/split/run.d.ts.map +1 -0
- package/dist/commands/project/split/run.js +231 -0
- package/dist/commands/project/split/validate-plan.d.ts +14 -0
- package/dist/commands/project/split/validate-plan.d.ts.map +1 -0
- package/dist/commands/project/split/validate-plan.js +62 -0
- package/dist/commands/shared/frontmatter.d.ts +9 -0
- package/dist/commands/shared/frontmatter.d.ts.map +1 -1
- package/dist/commands/shared/frontmatter.js +46 -0
- package/dist/commands/state/generate.d.ts.map +1 -1
- package/dist/commands/state/generate.js +38 -6
- package/dist/projects/split/child-plan.d.ts +46 -0
- package/dist/projects/split/child-plan.d.ts.map +1 -0
- package/dist/projects/split/child-plan.js +107 -0
- package/dist/projects/split/document-validation.d.ts +14 -0
- package/dist/projects/split/document-validation.d.ts.map +1 -0
- package/dist/projects/split/document-validation.js +106 -0
- package/dist/projects/split/finalize.d.ts +7 -0
- package/dist/projects/split/finalize.d.ts.map +1 -0
- package/dist/projects/split/finalize.js +32 -0
- package/dist/projects/split/resume.d.ts +19 -0
- package/dist/projects/split/resume.d.ts.map +1 -0
- package/dist/projects/split/resume.js +107 -0
- package/dist/projects/split/seed-children.d.ts +9 -0
- package/dist/projects/split/seed-children.d.ts.map +1 -0
- package/dist/projects/split/seed-children.js +122 -0
- package/dist/projects/split/signals.d.ts +10 -0
- package/dist/projects/split/signals.d.ts.map +1 -0
- package/dist/projects/split/signals.js +18 -0
- package/dist/projects/split/validation.d.ts +14 -0
- package/dist/projects/split/validation.d.ts.map +1 -0
- package/dist/projects/split/validation.js +104 -0
- package/dist/projects/split/write-parent.d.ts +16 -0
- package/dist/projects/split/write-parent.d.ts.map +1 -0
- package/dist/projects/split/write-parent.js +176 -0
- package/dist/validation/project-state.d.ts +50 -0
- package/dist/validation/project-state.d.ts.map +1 -0
- package/dist/validation/project-state.js +279 -0
- package/package.json +2 -2
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: oat-project-split
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
description: Use when a discovery or brainstorm should split one broad scope into coordinated OAT child projects.
|
|
5
|
+
argument-hint: '--plan-file <path>'
|
|
6
|
+
disable-model-invocation: true
|
|
7
|
+
user-invocable: true
|
|
8
|
+
allowed-tools: Read, Write, Bash(oat:*), Bash(pnpm:*), Glob, Grep, AskUserQuestion
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Split OAT Project
|
|
12
|
+
|
|
13
|
+
Decompose a confirmed multi-project discovery or brainstorm into a coordination-only parent and flat child projects.
|
|
14
|
+
|
|
15
|
+
## Mode Assertion
|
|
16
|
+
|
|
17
|
+
Use this skill only after one of these split triggers is present:
|
|
18
|
+
|
|
19
|
+
- The user explicitly declared the work is multiple projects.
|
|
20
|
+
- Discovery signals crossed the split threshold and the user confirmed.
|
|
21
|
+
- End-of-discovery convergence confirmed that the scope should split.
|
|
22
|
+
- The brainstorm destination picker selected a split into projects.
|
|
23
|
+
|
|
24
|
+
Detected split recommendations in non-interactive mode must fail fast through the CLI run command; do not silently split or silently continue as one project.
|
|
25
|
+
|
|
26
|
+
## Progress Indicators (User-Facing)
|
|
27
|
+
|
|
28
|
+
Print a banner once at start:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
32
|
+
OAT ▸ PROJECT SPLIT
|
|
33
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Before multi-step work, print step indicators:
|
|
37
|
+
|
|
38
|
+
- `[1/5] Writing coordination parent...`
|
|
39
|
+
- `[2/5] Scaffolding and seeding children...`
|
|
40
|
+
- `[3/5] Marking parent terminal...`
|
|
41
|
+
- `[4/5] Selecting active child...`
|
|
42
|
+
- `[5/5] Refreshing dashboard...`
|
|
43
|
+
|
|
44
|
+
## Process
|
|
45
|
+
|
|
46
|
+
### Step 1: Resolve Split Plan
|
|
47
|
+
|
|
48
|
+
Require a persisted `SplitPlanDocument` JSON file. If `$ARGUMENTS` does not include `--plan-file <path>`, ask for the plan file path before proceeding.
|
|
49
|
+
|
|
50
|
+
### Step 2: Run Split Orchestrator
|
|
51
|
+
|
|
52
|
+
Invoke the CLI as the single execution entry point:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
oat project split run --plan-file "{plan-file}"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Use `--non-interactive` only when the caller is running without a human confirmation path.
|
|
59
|
+
|
|
60
|
+
### Step 3: Write Coordination Parent
|
|
61
|
+
|
|
62
|
+
The run command writes the parent project as `oat_kind: coordination`, persists `references/split-plan.json`, records ordered children in `state.md`, writes the broad `discovery.md` with any integration sketch, and removes executable phase files.
|
|
63
|
+
|
|
64
|
+
### Step 4: Scaffold + Seed Children
|
|
65
|
+
|
|
66
|
+
The run command scaffolds each child in plan order and writes split-specific child discovery content from scratch with the required inherited-context revalidation gate.
|
|
67
|
+
|
|
68
|
+
### Step 5: Mark Parent Terminal + Select Active Child
|
|
69
|
+
|
|
70
|
+
The run command marks the parent `oat_phase: decomposition` and `oat_phase_status: complete`, then activates the initial child using the repo-relative project path.
|
|
71
|
+
|
|
72
|
+
### Step 6: Resume From Partial State
|
|
73
|
+
|
|
74
|
+
If a previous split wrote a coordination parent but did not finish all children, the run command resumes from `references/split-plan.json`. Do not reconstruct missing child seed data from slugs alone.
|
|
75
|
+
|
|
76
|
+
## Success Criteria
|
|
77
|
+
|
|
78
|
+
- Coordination parent exists and has no `spec.md`, `design.md`, `plan.md`, or `implementation.md`.
|
|
79
|
+
- Parent `state.md` records `oat_kind: coordination`, ordered `oat_children`, and terminal decomposition status.
|
|
80
|
+
- `references/split-plan.json` contains the full `SplitPlanDocument`.
|
|
81
|
+
- Every child has seeded discovery content, parent/sibling/dependency links, and `oat_inherited_context_revalidated: false`.
|
|
82
|
+
- `.oat/config.local.json.activeProject` points at the repo-relative initial child path.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-summary
|
|
3
|
-
version: 1.1.
|
|
3
|
+
version: 1.1.2
|
|
4
4
|
description: Use when the user requests or confirms summarizing an active OAT project — e.g. "summarize the project", "generate the summary", "run oat-project-summary", or confirms a previously offered summary run. Do NOT auto-invoke when implementation completes. Generates summary.md from project artifacts as institutional memory.
|
|
5
5
|
disable-model-invocation: false
|
|
6
6
|
user-invocable: true
|
|
@@ -149,6 +149,8 @@ For each section, synthesize content from the relevant artifacts. Apply these ru
|
|
|
149
149
|
|
|
150
150
|
**Grounding rule:** Prefer implementation.md outcomes over design.md plans. If the implementation diverged from the design, reflect what actually happened.
|
|
151
151
|
|
|
152
|
+
**Design delta rule:** Populate `Design Deltas` from both direct implementation deviations and review-received design drift decisions recorded in `implementation.md`. A review finding may decide that shipped implementation is defensible and the artifact is stale; when `implementation.md` records that acceptance, carry it forward as a design delta with the rationale and follow-up artifact disposition.
|
|
153
|
+
|
|
152
154
|
**Section omission rule:** If a section would have no meaningful content, omit it entirely (remove the heading). Do not leave empty sections or "N/A" placeholders.
|
|
153
155
|
|
|
154
156
|
**Conciseness constraint (NFR3):** Target under 200 lines total. If a draft exceeds this, trim narrative sections (What Was Implemented, Notable Challenges) to essential points. Revision History entries: 2-3 sentences per round max.
|
|
@@ -157,18 +159,18 @@ For each section, synthesize content from the relevant artifacts. Apply these ru
|
|
|
157
159
|
|
|
158
160
|
**Section sources:**
|
|
159
161
|
|
|
160
|
-
| Section | Primary Sources
|
|
161
|
-
| -------------------- |
|
|
162
|
-
| Overview | discovery.md initial request, spec.md problem statement
|
|
163
|
-
| What Was Implemented | implementation.md task outcomes, plan.md phase structure
|
|
164
|
-
| Key Decisions | design.md decisions, implementation.md notes/decisions
|
|
165
|
-
| Design Deltas | implementation.md deviations table
|
|
166
|
-
| Notable Challenges | implementation.md issues/blockers in task notes
|
|
167
|
-
| Tradeoffs Made | implementation.md decisions, design.md tradeoff sections
|
|
168
|
-
| Integration Notes | implementation.md notes about cross-cutting concerns
|
|
169
|
-
| Revision History | plan.md p-revN phases, implementation.md revision notes
|
|
170
|
-
| Follow-up Items | implementation.md deferred findings, plan.md deferred items
|
|
171
|
-
| Associated Issues | state.md `associated_issues` field
|
|
162
|
+
| Section | Primary Sources |
|
|
163
|
+
| -------------------- | ---------------------------------------------------------------------- |
|
|
164
|
+
| Overview | discovery.md initial request, spec.md problem statement |
|
|
165
|
+
| What Was Implemented | implementation.md task outcomes, plan.md phase structure |
|
|
166
|
+
| Key Decisions | design.md decisions, implementation.md notes/decisions |
|
|
167
|
+
| Design Deltas | implementation.md deviations table; review-received design drift notes |
|
|
168
|
+
| Notable Challenges | implementation.md issues/blockers in task notes |
|
|
169
|
+
| Tradeoffs Made | implementation.md decisions, design.md tradeoff sections |
|
|
170
|
+
| Integration Notes | implementation.md notes about cross-cutting concerns |
|
|
171
|
+
| Revision History | plan.md p-revN phases, implementation.md revision notes |
|
|
172
|
+
| Follow-up Items | implementation.md deferred findings, plan.md deferred items |
|
|
173
|
+
| Associated Issues | state.md `associated_issues` field |
|
|
172
174
|
|
|
173
175
|
**For incremental updates (re-run):**
|
|
174
176
|
|
|
@@ -165,13 +165,13 @@ Chronological log of implementation progress.
|
|
|
165
165
|
|
|
166
166
|
---
|
|
167
167
|
|
|
168
|
-
## Deviations from Plan
|
|
168
|
+
## Deviations from Plan / Design
|
|
169
169
|
|
|
170
|
-
Document any deviations from the original plan.
|
|
170
|
+
Document any intentional deviations from the original plan, spec, or design. Include accepted review findings where the shipped implementation is source of truth and a lifecycle artifact needs alignment.
|
|
171
171
|
|
|
172
|
-
| Task | Planned | Actual | Reason |
|
|
173
|
-
|
|
|
174
|
-
| -
|
|
172
|
+
| Task / Review | Source Artifact | Planned / Documented | Actual / Accepted | Reason | Source of Truth | Follow-up |
|
|
173
|
+
| ------------- | --------------- | -------------------- | ----------------- | ------ | --------------- | --------- |
|
|
174
|
+
| - | - | - | - | - | - | - |
|
|
175
175
|
|
|
176
176
|
## Test Results
|
|
177
177
|
|
|
@@ -3,10 +3,15 @@ oat_current_task: null
|
|
|
3
3
|
oat_last_commit: null
|
|
4
4
|
oat_blockers: []
|
|
5
5
|
associated_issues: [] # [{type: backlog|project|jira|linear, ref: "identifier"}]
|
|
6
|
+
oat_kind: implementation # implementation | coordination; coordination parents may use oat_phase: decomposition
|
|
7
|
+
oat_parent: null # optional child-only coordination parent slug
|
|
8
|
+
oat_siblings: [] # optional child-only sibling slugs
|
|
9
|
+
oat_depends_on: [] # optional child-only sibling dependencies
|
|
10
|
+
oat_children: [] # optional coordination-parent child slugs
|
|
6
11
|
oat_hill_checkpoints: { OAT_HILL_CHECKPOINTS } # Configured: which phases require human-in-the-loop lifecycle approval
|
|
7
12
|
oat_hill_completed: [] # Progress: which HiLL checkpoints have been completed
|
|
8
13
|
oat_parallel_execution: false
|
|
9
|
-
oat_phase: { OAT_PHASE } # Current phase: discovery | spec | design | plan | implement
|
|
14
|
+
oat_phase: { OAT_PHASE } # Current phase: discovery | spec | design | plan | implement | decomposition
|
|
10
15
|
oat_phase_status: in_progress # Status: in_progress | complete | pr_open
|
|
11
16
|
# oat_orchestration_retry_limit: 2 # optional; override fix-loop retry limit (range 0-5)
|
|
12
17
|
oat_workflow_mode: { OAT_WORKFLOW_MODE } # spec-driven | quick | import
|
|
@@ -37,7 +37,8 @@ where decisions were made or changed during implementation.}
|
|
|
37
37
|
<!-- Omit this section if there were no deviations from the original design. -->
|
|
38
38
|
|
|
39
39
|
{Where the final result diverged from the original design and why.
|
|
40
|
-
Pull from implementation.md deviations table.
|
|
40
|
+
Pull from implementation.md deviations table and review-received design drift notes.
|
|
41
|
+
Include accepted cases where shipped implementation became source of truth and a stale lifecycle artifact needs alignment or was explicitly deferred.}
|
|
41
42
|
|
|
42
43
|
## Notable Challenges
|
|
43
44
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type SplitChildInput, type SplitPayload, type SplitPlanDocument } from '../../projects/split/child-plan.js';
|
|
2
|
+
import { type Signal } from '../../projects/split/signals.js';
|
|
3
|
+
export type TranscriptSpeaker = 'assistant' | 'user';
|
|
4
|
+
export interface TranscriptTurn {
|
|
5
|
+
speaker: TranscriptSpeaker;
|
|
6
|
+
text: string;
|
|
7
|
+
}
|
|
8
|
+
export type StubbedUserChoice = 'broad-first' | 'children-known' | 'decompose-children' | 'inline-only' | 'keep-one-project' | 'promote-n-projects' | 'split-now';
|
|
9
|
+
export interface StubbedQuestion {
|
|
10
|
+
id: string;
|
|
11
|
+
prompt: string;
|
|
12
|
+
options: string[];
|
|
13
|
+
response: StubbedUserChoice;
|
|
14
|
+
}
|
|
15
|
+
export interface TranscriptFixture {
|
|
16
|
+
transcript: TranscriptTurn[];
|
|
17
|
+
parentSlug: string;
|
|
18
|
+
children: SplitChildInput[];
|
|
19
|
+
discoveryPath?: string;
|
|
20
|
+
inheritedContext?: string;
|
|
21
|
+
integrationSketch?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare const SPLIT_HANDOFF_TARGET: {
|
|
24
|
+
readonly skill: "oat-project-split";
|
|
25
|
+
readonly hookCreatesProjects: false;
|
|
26
|
+
readonly responsibilities: readonly ["normalize-split-plan", "write-coordination-parent", "scaffold-children", "activate-initial-child"];
|
|
27
|
+
};
|
|
28
|
+
export declare function inferSplitSignals(transcript: TranscriptTurn[]): Signal[];
|
|
29
|
+
export declare function runDiscoverDetectionFixture(fixture: TranscriptFixture, responses: Record<string, StubbedUserChoice>): {
|
|
30
|
+
asked: StubbedQuestion[];
|
|
31
|
+
confidence: 'below' | 'high' | 'soft';
|
|
32
|
+
decision?: StubbedUserChoice;
|
|
33
|
+
document?: SplitPlanDocument;
|
|
34
|
+
payload?: SplitPayload;
|
|
35
|
+
triggered: boolean;
|
|
36
|
+
};
|
|
37
|
+
export declare function runDeclaredBrainstormFixture(fixture: TranscriptFixture, responses: Record<string, StubbedUserChoice>): {
|
|
38
|
+
asked: StubbedQuestion[];
|
|
39
|
+
document?: SplitPlanDocument;
|
|
40
|
+
handoffTarget: typeof SPLIT_HANDOFF_TARGET;
|
|
41
|
+
payload?: SplitPayload;
|
|
42
|
+
};
|
|
43
|
+
export declare function runBrainstormPickerFixture(fixture: TranscriptFixture, responses: Record<string, StubbedUserChoice>): {
|
|
44
|
+
asked: StubbedQuestion[];
|
|
45
|
+
document?: SplitPlanDocument;
|
|
46
|
+
handoffTarget: typeof SPLIT_HANDOFF_TARGET;
|
|
47
|
+
options: string[];
|
|
48
|
+
payload?: SplitPayload;
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=split-flow-fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split-flow-fixtures.d.ts","sourceRoot":"","sources":["../../../src/__tests__/skills/split-flow-fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACvB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAmB,KAAK,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAE5E,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,MAAM,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,iBAAiB,GACzB,aAAa,GACb,gBAAgB,GAChB,oBAAoB,GACpB,aAAa,GACb,kBAAkB,GAClB,oBAAoB,GACpB,WAAW,CAAC;AAEhB,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,iBAAiB,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,oBAAoB;;;;CASvB,CAAC;AAsBX,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,cAAc,EAAE,GAAG,MAAM,EAAE,CA+BxE;AAED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAC3C;IACD,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,UAAU,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACtC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;CACpB,CAqDA;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAC3C;IACD,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,aAAa,EAAE,OAAO,oBAAoB,CAAC;IAC3C,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB,CAmCA;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAC3C;IACD,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,aAAa,EAAE,OAAO,oBAAoB,CAAC;IAC3C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB,CA4CA"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { buildSplitPlanDocument, } from '../../projects/split/child-plan.js';
|
|
2
|
+
import { evaluateSignals } from '../../projects/split/signals.js';
|
|
3
|
+
export const SPLIT_HANDOFF_TARGET = {
|
|
4
|
+
skill: 'oat-project-split',
|
|
5
|
+
hookCreatesProjects: false,
|
|
6
|
+
responsibilities: [
|
|
7
|
+
'normalize-split-plan',
|
|
8
|
+
'write-coordination-parent',
|
|
9
|
+
'scaffold-children',
|
|
10
|
+
'activate-initial-child',
|
|
11
|
+
],
|
|
12
|
+
};
|
|
13
|
+
class AskUserQuestionStub {
|
|
14
|
+
responses;
|
|
15
|
+
asked = [];
|
|
16
|
+
constructor(responses) {
|
|
17
|
+
this.responses = responses;
|
|
18
|
+
}
|
|
19
|
+
ask(id, prompt, options) {
|
|
20
|
+
const response = this.responses[id];
|
|
21
|
+
if (!response) {
|
|
22
|
+
throw new Error(`Missing stubbed response for AskUserQuestion ${id}`);
|
|
23
|
+
}
|
|
24
|
+
this.asked.push({ id, prompt, options, response });
|
|
25
|
+
return response;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function transcriptText(transcript) {
|
|
29
|
+
return transcript.map((turn) => `${turn.speaker}: ${turn.text}`).join('\n');
|
|
30
|
+
}
|
|
31
|
+
export function inferSplitSignals(transcript) {
|
|
32
|
+
const text = transcriptText(transcript).toLowerCase();
|
|
33
|
+
const signals = new Set();
|
|
34
|
+
if (text.includes('independently shippable') ||
|
|
35
|
+
text.includes('ship independently')) {
|
|
36
|
+
signals.add('independently-shippable');
|
|
37
|
+
}
|
|
38
|
+
if (text.includes('no shared design surface') ||
|
|
39
|
+
text.includes('separate design surfaces')) {
|
|
40
|
+
signals.add('no-shared-design-surface');
|
|
41
|
+
}
|
|
42
|
+
if (text.includes('separate pr') || text.includes('separate pull request')) {
|
|
43
|
+
signals.add('expect-separate-prs');
|
|
44
|
+
}
|
|
45
|
+
if (text.includes('distinct subsystem') ||
|
|
46
|
+
text.includes('different package') ||
|
|
47
|
+
text.includes('different packages')) {
|
|
48
|
+
signals.add('distinct-subsystems');
|
|
49
|
+
}
|
|
50
|
+
return [...signals];
|
|
51
|
+
}
|
|
52
|
+
export function runDiscoverDetectionFixture(fixture, responses) {
|
|
53
|
+
const evaluation = evaluateSignals({
|
|
54
|
+
fired: inferSplitSignals(fixture.transcript),
|
|
55
|
+
});
|
|
56
|
+
const askUser = new AskUserQuestionStub(responses);
|
|
57
|
+
if (!evaluation.triggered) {
|
|
58
|
+
return {
|
|
59
|
+
asked: askUser.asked,
|
|
60
|
+
confidence: evaluation.confidence,
|
|
61
|
+
triggered: false,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const prompt = evaluation.confidence === 'high'
|
|
65
|
+
? 'This looks like multiple independent projects. Split now, do one round of broad cross-cutting discovery first, or keep this as one project?'
|
|
66
|
+
: 'This may be multiple projects. Split, do one round of broad cross-cutting discovery first, or keep it as one project?';
|
|
67
|
+
const decision = askUser.ask('discover-split-offer', prompt, [
|
|
68
|
+
'split-now',
|
|
69
|
+
'broad-first',
|
|
70
|
+
'keep-one-project',
|
|
71
|
+
]);
|
|
72
|
+
if (decision !== 'split-now') {
|
|
73
|
+
return {
|
|
74
|
+
asked: askUser.asked,
|
|
75
|
+
confidence: evaluation.confidence,
|
|
76
|
+
decision,
|
|
77
|
+
triggered: true,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const payload = {
|
|
81
|
+
origin: 'detected-mid-stream',
|
|
82
|
+
interactive: true,
|
|
83
|
+
inferredChildren: fixture.children,
|
|
84
|
+
priorDiscovery: {
|
|
85
|
+
path: fixture.discoveryPath ?? `.oat/projects/shared/${fixture.parentSlug}`,
|
|
86
|
+
inheritedContext: fixture.inheritedContext,
|
|
87
|
+
integrationSketch: fixture.integrationSketch,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
return {
|
|
91
|
+
asked: askUser.asked,
|
|
92
|
+
confidence: evaluation.confidence,
|
|
93
|
+
decision,
|
|
94
|
+
document: buildSplitPlanDocument(payload),
|
|
95
|
+
payload,
|
|
96
|
+
triggered: true,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export function runDeclaredBrainstormFixture(fixture, responses) {
|
|
100
|
+
const text = transcriptText(fixture.transcript).toLowerCase();
|
|
101
|
+
const declared = text.includes('multiple projects') ||
|
|
102
|
+
text.includes('umbrella project') ||
|
|
103
|
+
text.includes('several sub-projects');
|
|
104
|
+
if (!declared) {
|
|
105
|
+
return { asked: [], handoffTarget: SPLIT_HANDOFF_TARGET };
|
|
106
|
+
}
|
|
107
|
+
const askUser = new AskUserQuestionStub(responses);
|
|
108
|
+
const decision = askUser.ask('declared-brainstorm-boundary', 'Do you already know the child projects, or should we decompose the scope together?', ['children-known', 'decompose-children']);
|
|
109
|
+
if (decision !== 'children-known') {
|
|
110
|
+
return { asked: askUser.asked, handoffTarget: SPLIT_HANDOFF_TARGET };
|
|
111
|
+
}
|
|
112
|
+
const payload = {
|
|
113
|
+
origin: 'declared',
|
|
114
|
+
parentSlug: fixture.parentSlug,
|
|
115
|
+
declaredChildren: fixture.children,
|
|
116
|
+
interactive: true,
|
|
117
|
+
integrationSketch: fixture.integrationSketch,
|
|
118
|
+
};
|
|
119
|
+
return {
|
|
120
|
+
asked: askUser.asked,
|
|
121
|
+
document: buildSplitPlanDocument(payload),
|
|
122
|
+
handoffTarget: SPLIT_HANDOFF_TARGET,
|
|
123
|
+
payload,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
export function runBrainstormPickerFixture(fixture, responses) {
|
|
127
|
+
const evaluation = evaluateSignals({
|
|
128
|
+
fired: inferSplitSignals(fixture.transcript),
|
|
129
|
+
});
|
|
130
|
+
const options = ['inline-only', 'doc-to-path', 'promote-to-new-oat-project'];
|
|
131
|
+
if (evaluation.triggered) {
|
|
132
|
+
options.push('promote-n-projects');
|
|
133
|
+
}
|
|
134
|
+
const askUser = new AskUserQuestionStub(responses);
|
|
135
|
+
const decision = askUser.ask('brainstorm-terminal-state', 'Where should this brainstorm land?', options);
|
|
136
|
+
if (decision !== 'promote-n-projects' || !evaluation.triggered) {
|
|
137
|
+
return {
|
|
138
|
+
asked: askUser.asked,
|
|
139
|
+
handoffTarget: SPLIT_HANDOFF_TARGET,
|
|
140
|
+
options,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const payload = {
|
|
144
|
+
origin: 'brainstorm-picker',
|
|
145
|
+
parentSlug: fixture.parentSlug,
|
|
146
|
+
inferredChildren: fixture.children,
|
|
147
|
+
interactive: true,
|
|
148
|
+
priorDiscovery: {
|
|
149
|
+
path: `brainstorm/${fixture.parentSlug}`,
|
|
150
|
+
inheritedContext: fixture.inheritedContext,
|
|
151
|
+
integrationSketch: fixture.integrationSketch,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
return {
|
|
155
|
+
asked: askUser.asked,
|
|
156
|
+
document: buildSplitPlanDocument(payload),
|
|
157
|
+
handoffTarget: SPLIT_HANDOFF_TARGET,
|
|
158
|
+
options,
|
|
159
|
+
payload,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
@@ -11,7 +11,7 @@ export interface PackMetadata {
|
|
|
11
11
|
}
|
|
12
12
|
export declare const PACK_METADATA: Record<string, PackMetadata>;
|
|
13
13
|
export declare function resolvePackDefaultScope(packName: string): 'user' | 'project';
|
|
14
|
-
export declare const WORKFLOW_SKILLS: readonly ["oat-project-capture", "oat-project-clear-active", "oat-project-complete", "oat-project-design", "oat-project-discover", "oat-project-document", "oat-project-implement", "oat-project-import-plan", "oat-project-new", "oat-project-next", "oat-project-open", "oat-project-plan", "oat-project-plan-writing", "oat-project-pr-final", "oat-project-pr-progress", "oat-project-progress", "oat-project-promote-spec-driven", "oat-project-quick-start", "oat-project-reconcile", "oat-project-revise", "oat-project-review-provide", "oat-project-review-receive", "oat-project-review-receive-remote", "oat-project-spec", "oat-project-summary", "oat-repo-knowledge-index", "oat-worktree-bootstrap", "oat-worktree-bootstrap-auto", "oat-wrap-up"];
|
|
14
|
+
export declare const WORKFLOW_SKILLS: readonly ["oat-project-capture", "oat-project-clear-active", "oat-project-complete", "oat-project-design", "oat-project-discover", "oat-project-document", "oat-project-implement", "oat-project-import-plan", "oat-project-new", "oat-project-next", "oat-project-open", "oat-project-plan", "oat-project-plan-writing", "oat-project-pr-final", "oat-project-pr-progress", "oat-project-progress", "oat-project-promote-spec-driven", "oat-project-quick-start", "oat-project-reconcile", "oat-project-revise", "oat-project-review-provide", "oat-project-review-receive", "oat-project-review-receive-remote", "oat-project-spec", "oat-project-split", "oat-project-summary", "oat-repo-knowledge-index", "oat-worktree-bootstrap", "oat-worktree-bootstrap-auto", "oat-wrap-up"];
|
|
15
15
|
export declare const WORKFLOW_AGENTS: readonly ["oat-codebase-mapper.md", "oat-phase-implementer.md", "oat-reviewer.md"];
|
|
16
16
|
export declare const WORKFLOW_TEMPLATES: readonly ["state.md", "discovery.md", "spec.md", "design.md", "plan.md", "implementation.md", "summary.md"];
|
|
17
17
|
export declare const WORKFLOW_SCRIPTS: readonly ["generate-oat-state.sh", "generate-thin-index.sh", "resolve-tracking.sh"];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-manifest.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/shared/skill-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgBH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAKtD,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE5E;AAID,eAAO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"skill-manifest.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/shared/skill-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgBH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAKtD,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE5E;AAID,eAAO,MAAM,eAAe,wvBA+BlB,CAAC;AAEX,eAAO,MAAM,eAAe,oFAIlB,CAAC;AAEX,eAAO,MAAM,kBAAkB,6GAQrB,CAAC;AAEX,eAAO,MAAM,gBAAgB,qFAInB,CAAC;AAIX,eAAO,MAAM,WAAW,2FAKd,CAAC;AAIX,eAAO,MAAM,WAAW,qCAAsC,CAAC;AAI/D,eAAO,MAAM,WAAW,yIAMd,CAAC;AAEX,eAAO,MAAM,YAAY,kCAAmC,CAAC;AAI7D,eAAO,MAAM,cAAc,gJAMjB,CAAC;AAIX,eAAO,MAAM,yBAAyB,kGAI5B,CAAC;AAEX,eAAO,MAAM,4BAA4B,4CAG/B,CAAC;AAEX,eAAO,MAAM,0BAA0B,aAAc,CAAC;AAItD,eAAO,MAAM,iBAAiB,6BAA8B,CAAC;AAI7D,eAAO,MAAM,eAAe,2EAMlB,CAAC;AAEX,eAAO,MAAM,eAAe,qCAAsC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { readFile as defaultReadFile, writeFile as defaultWriteFile } from 'node:fs/promises';
|
|
2
|
+
import { type CommandContext, type GlobalOptions } from '../../../app/command-context.js';
|
|
3
|
+
import { dirExists, fileExists } from '../../../fs/io.js';
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
interface ProjectCompleteDiscoveryDependencies {
|
|
6
|
+
buildCommandContext: (options: GlobalOptions) => CommandContext;
|
|
7
|
+
resolveProjectRoot: (cwd: string) => Promise<string>;
|
|
8
|
+
readFile: typeof defaultReadFile;
|
|
9
|
+
writeFile: typeof defaultWriteFile;
|
|
10
|
+
dirExists: typeof dirExists;
|
|
11
|
+
fileExists: typeof fileExists;
|
|
12
|
+
now: () => Date;
|
|
13
|
+
}
|
|
14
|
+
export declare function createProjectCompleteDiscoveryCommand(overrides?: Partial<ProjectCompleteDiscoveryDependencies>): Command;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/complete-discovery/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,IAAI,eAAe,EAC3B,SAAS,IAAI,gBAAgB,EAC9B,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAI9B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAG/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,UAAU,oCAAoC;IAC5C,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,QAAQ,EAAE,OAAO,eAAe,CAAC;IACjC,SAAS,EAAE,OAAO,gBAAgB,CAAC;IACnC,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,GAAG,EAAE,MAAM,IAAI,CAAC;CACjB;AAkJD,wBAAgB,qCAAqC,CACnD,SAAS,GAAE,OAAO,CAAC,oCAAoC,CAAM,GAC5D,OAAO,CA+BT"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { readFile as defaultReadFile, writeFile as defaultWriteFile, } from 'node:fs/promises';
|
|
2
|
+
import { isAbsolute, join } from 'node:path';
|
|
3
|
+
import { buildCommandContext, } from '../../../app/command-context.js';
|
|
4
|
+
import { getFrontmatterBlock } from '../../shared/frontmatter.js';
|
|
5
|
+
import { readGlobalOptions } from '../../shared/shared.utils.js';
|
|
6
|
+
import { CliError } from '../../../errors/cli-error.js';
|
|
7
|
+
import { dirExists, fileExists } from '../../../fs/io.js';
|
|
8
|
+
import { resolveProjectRoot } from '../../../fs/paths.js';
|
|
9
|
+
import { assertValidProjectStateFilesystemContent } from '../../../validation/project-state.js';
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
import YAML from 'yaml';
|
|
12
|
+
const DEFAULT_DEPENDENCIES = {
|
|
13
|
+
buildCommandContext,
|
|
14
|
+
resolveProjectRoot,
|
|
15
|
+
readFile: defaultReadFile,
|
|
16
|
+
writeFile: defaultWriteFile,
|
|
17
|
+
dirExists,
|
|
18
|
+
fileExists,
|
|
19
|
+
now: () => new Date(),
|
|
20
|
+
};
|
|
21
|
+
function resolveTargetProjectPath(repoRoot, projectPath) {
|
|
22
|
+
return isAbsolute(projectPath) ? projectPath : join(repoRoot, projectPath);
|
|
23
|
+
}
|
|
24
|
+
function parseFrontmatterObject(content, filePath) {
|
|
25
|
+
const frontmatter = getFrontmatterBlock(content);
|
|
26
|
+
if (!frontmatter) {
|
|
27
|
+
throw new CliError(`${filePath} is missing frontmatter`, 1);
|
|
28
|
+
}
|
|
29
|
+
const parsed = YAML.parse(frontmatter);
|
|
30
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
31
|
+
throw new CliError(`${filePath} frontmatter must be a YAML object`, 1);
|
|
32
|
+
}
|
|
33
|
+
return parsed;
|
|
34
|
+
}
|
|
35
|
+
function renderDiscoveryComplete(content, filePath, options) {
|
|
36
|
+
const frontmatter = parseFrontmatterObject(content, filePath);
|
|
37
|
+
frontmatter['oat_status'] = 'complete';
|
|
38
|
+
frontmatter['oat_ready_for'] = options.readyFor;
|
|
39
|
+
frontmatter['oat_last_updated'] = options.today;
|
|
40
|
+
const renderedFrontmatter = YAML.stringify(frontmatter).trimEnd();
|
|
41
|
+
return content.replace(/^---\n[\s\S]*?\n---/, `---\n${renderedFrontmatter}\n---`);
|
|
42
|
+
}
|
|
43
|
+
function renderFrontmatterDocument(frontmatter) {
|
|
44
|
+
return `---\n${YAML.stringify(frontmatter).trimEnd()}\n---\n`;
|
|
45
|
+
}
|
|
46
|
+
async function buildDiscoveryValidationContent(content, options) {
|
|
47
|
+
const discoveryFrontmatter = parseFrontmatterObject(content, options.discoveryPath);
|
|
48
|
+
const statePath = join(options.projectPath, 'state.md');
|
|
49
|
+
if (!(await options.dependencies.fileExists(statePath))) {
|
|
50
|
+
return content;
|
|
51
|
+
}
|
|
52
|
+
const stateContent = await options.dependencies.readFile(statePath, 'utf8');
|
|
53
|
+
const stateFrontmatter = parseFrontmatterObject(stateContent, statePath);
|
|
54
|
+
return renderFrontmatterDocument({
|
|
55
|
+
...stateFrontmatter,
|
|
56
|
+
...discoveryFrontmatter,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async function runProjectCompleteDiscovery(projectPath, options, context, dependencies) {
|
|
60
|
+
try {
|
|
61
|
+
const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
62
|
+
const targetProjectPath = resolveTargetProjectPath(repoRoot, projectPath);
|
|
63
|
+
if (!(await dependencies.dirExists(targetProjectPath))) {
|
|
64
|
+
throw new CliError(`Project not found: ${projectPath}`, 1);
|
|
65
|
+
}
|
|
66
|
+
const discoveryPath = join(targetProjectPath, 'discovery.md');
|
|
67
|
+
if (!(await dependencies.fileExists(discoveryPath))) {
|
|
68
|
+
throw new CliError(`Project discovery.md not found: ${discoveryPath}`, 1);
|
|
69
|
+
}
|
|
70
|
+
const now = dependencies.now();
|
|
71
|
+
const content = await dependencies.readFile(discoveryPath, 'utf8');
|
|
72
|
+
const updatedContent = renderDiscoveryComplete(content, discoveryPath, {
|
|
73
|
+
readyFor: options.readyFor ?? 'oat-project-design',
|
|
74
|
+
today: now.toISOString().slice(0, 10),
|
|
75
|
+
});
|
|
76
|
+
const validationContent = await buildDiscoveryValidationContent(updatedContent, {
|
|
77
|
+
discoveryPath,
|
|
78
|
+
projectPath: targetProjectPath,
|
|
79
|
+
dependencies,
|
|
80
|
+
});
|
|
81
|
+
await assertValidProjectStateFilesystemContent(validationContent, {
|
|
82
|
+
filePath: discoveryPath,
|
|
83
|
+
projectPath: targetProjectPath,
|
|
84
|
+
});
|
|
85
|
+
await dependencies.writeFile(discoveryPath, updatedContent, 'utf8');
|
|
86
|
+
if (context.json) {
|
|
87
|
+
context.logger.json({
|
|
88
|
+
status: 'ok',
|
|
89
|
+
projectPath,
|
|
90
|
+
discoveryPath,
|
|
91
|
+
readyFor: options.readyFor ?? 'oat-project-design',
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
context.logger.info(`Completed project discovery: ${projectPath}`);
|
|
96
|
+
}
|
|
97
|
+
process.exitCode = 0;
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
101
|
+
if (context.json) {
|
|
102
|
+
context.logger.json({ status: 'error', message });
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
context.logger.error(message);
|
|
106
|
+
}
|
|
107
|
+
process.exitCode = error instanceof CliError ? error.exitCode : 1;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export function createProjectCompleteDiscoveryCommand(overrides = {}) {
|
|
111
|
+
const dependencies = {
|
|
112
|
+
...DEFAULT_DEPENDENCIES,
|
|
113
|
+
...overrides,
|
|
114
|
+
};
|
|
115
|
+
return new Command('complete-discovery')
|
|
116
|
+
.description('Validate and mark a project discovery.md complete')
|
|
117
|
+
.argument('<project-path>', 'Project path to update')
|
|
118
|
+
.option('--ready-for <skill>', 'Value to write to discovery.md oat_ready_for', 'oat-project-design')
|
|
119
|
+
.action(async (projectPath, options, command) => {
|
|
120
|
+
const context = dependencies.buildCommandContext(readGlobalOptions(command));
|
|
121
|
+
await runProjectCompleteDiscovery(projectPath, options, context, dependencies);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/complete-state/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,IAAI,eAAe,EAC3B,SAAS,IAAI,gBAAgB,EAC9B,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGhF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/complete-state/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,IAAI,eAAe,EAC3B,SAAS,IAAI,gBAAgB,EAC9B,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGhF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAG/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,UAAU,gCAAgC;IACxC,mBAAmB,EAAE,CACnB,OAAO,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAC/C,cAAc,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,QAAQ,EAAE,OAAO,eAAe,CAAC;IACjC,SAAS,EAAE,OAAO,gBAAgB,CAAC;IACnC,SAAS,EAAE,OAAO,SAAS,CAAC;IAC5B,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,GAAG,EAAE,MAAM,IAAI,CAAC;CACjB;AA0ED,wBAAgB,iCAAiC,CAC/C,SAAS,GAAE,OAAO,CAAC,gCAAgC,CAAM,GACxD,OAAO,CA2BT"}
|
|
@@ -5,6 +5,7 @@ import { readGlobalOptions } from '../../shared/shared.utils.js';
|
|
|
5
5
|
import { CliError } from '../../../errors/cli-error.js';
|
|
6
6
|
import { dirExists, fileExists } from '../../../fs/io.js';
|
|
7
7
|
import { resolveProjectRoot } from '../../../fs/paths.js';
|
|
8
|
+
import { assertValidProjectStateFilesystemContent } from '../../../validation/project-state.js';
|
|
8
9
|
import { Command } from 'commander';
|
|
9
10
|
import { renderCompletedProjectState } from './state-utils.js';
|
|
10
11
|
const DEFAULT_DEPENDENCIES = {
|
|
@@ -37,6 +38,10 @@ async function runProjectCompleteState(projectPath, options, context, dependenci
|
|
|
37
38
|
nowUtc: now.toISOString(),
|
|
38
39
|
today: now.toISOString().slice(0, 10),
|
|
39
40
|
});
|
|
41
|
+
await assertValidProjectStateFilesystemContent(updatedContent, {
|
|
42
|
+
filePath: statePath,
|
|
43
|
+
projectPath: targetProjectPath,
|
|
44
|
+
});
|
|
40
45
|
await dependencies.writeFile(statePath, updatedContent, 'utf8');
|
|
41
46
|
if (context.json) {
|
|
42
47
|
context.logger.json({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/project/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/project/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAcpC,wBAAgB,oBAAoB,IAAI,OAAO,CAc9C"}
|
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { createProjectArchiveCommand } from './archive/index.js';
|
|
3
|
+
import { createProjectCompleteDiscoveryCommand } from './complete-discovery/index.js';
|
|
3
4
|
import { createProjectCompleteStateCommand } from './complete-state/index.js';
|
|
4
5
|
import { createProjectListCommand } from './list.js';
|
|
5
6
|
import { createProjectNewCommand } from './new/index.js';
|
|
6
7
|
import { createProjectOpenCommand } from './open/index.js';
|
|
7
8
|
import { createProjectPauseCommand } from './pause/index.js';
|
|
8
9
|
import { createProjectSetModeCommand } from './set-mode/index.js';
|
|
10
|
+
import { createProjectSplitCommand } from './split/index.js';
|
|
9
11
|
import { createProjectStatusCommand } from './status.js';
|
|
10
12
|
import { createProjectValidatePlanCommand } from './validate-plan/index.js';
|
|
11
13
|
export function createProjectCommand() {
|
|
12
14
|
return new Command('project')
|
|
13
15
|
.description('Manage OAT project workflows')
|
|
14
16
|
.addCommand(createProjectArchiveCommand())
|
|
17
|
+
.addCommand(createProjectCompleteDiscoveryCommand())
|
|
15
18
|
.addCommand(createProjectCompleteStateCommand())
|
|
16
19
|
.addCommand(createProjectListCommand())
|
|
17
20
|
.addCommand(createProjectNewCommand())
|
|
18
21
|
.addCommand(createProjectOpenCommand())
|
|
19
22
|
.addCommand(createProjectPauseCommand())
|
|
20
23
|
.addCommand(createProjectSetModeCommand())
|
|
24
|
+
.addCommand(createProjectSplitCommand())
|
|
21
25
|
.addCommand(createProjectStatusCommand())
|
|
22
26
|
.addCommand(createProjectValidatePlanCommand());
|
|
23
27
|
}
|
|
@@ -6,8 +6,14 @@ interface ProjectListDependencies {
|
|
|
6
6
|
resolveProjectRoot: (cwd: string) => Promise<string>;
|
|
7
7
|
resolveProjectsRoot: (repoRoot: string, env: NodeJS.ProcessEnv) => Promise<string>;
|
|
8
8
|
listProjects: (projectsRoot: string) => Promise<ProjectSummary[]>;
|
|
9
|
+
readProjectMetadata: (projectPath: string) => Promise<ProjectListMetadata>;
|
|
9
10
|
processEnv: NodeJS.ProcessEnv;
|
|
10
11
|
}
|
|
12
|
+
interface ProjectListMetadata {
|
|
13
|
+
kind: string;
|
|
14
|
+
phase: string;
|
|
15
|
+
phaseStatus: string;
|
|
16
|
+
}
|
|
11
17
|
export declare function createProjectListCommand(overrides?: Partial<ProjectListDependencies>): Command;
|
|
12
18
|
export {};
|
|
13
19
|
//# sourceMappingURL=list.d.ts.map
|