@open-agent-toolkit/cli 0.0.32 → 0.0.34
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/README.md +2 -0
- package/assets/docs/reference/cli-reference.md +1 -0
- package/assets/docs/workflows/projects/lifecycle.md +1 -1
- package/assets/docs/workflows/skills/index.md +1 -1
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-docs/SKILL.md +5 -3
- package/assets/skills/oat-project-complete/SKILL.md +8 -30
- package/assets/skills/oat-project-quick-start/SKILL.md +9 -3
- package/dist/commands/project/complete-state/index.d.ts +16 -0
- package/dist/commands/project/complete-state/index.d.ts.map +1 -0
- package/dist/commands/project/complete-state/index.js +78 -0
- package/dist/commands/project/complete-state/state-utils.d.ts +7 -0
- package/dist/commands/project/complete-state/state-utils.d.ts.map +1 -0
- package/dist/commands/project/complete-state/state-utils.js +72 -0
- package/dist/commands/project/index.d.ts.map +1 -1
- package/dist/commands/project/index.js +2 -0
- package/dist/validation/skills.d.ts.map +1 -1
- package/dist/validation/skills.js +9 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -34,6 +34,7 @@ Additional useful entry points:
|
|
|
34
34
|
- `oat config dump --json`
|
|
35
35
|
- `oat project status --json`
|
|
36
36
|
- `oat project list --json`
|
|
37
|
+
- `oat project complete-state /path/to/project`
|
|
37
38
|
- `oat project archive sync`
|
|
38
39
|
- `oat doctor`
|
|
39
40
|
|
|
@@ -44,6 +45,7 @@ Use these commands when you want structured runtime/project state out of the CLI
|
|
|
44
45
|
- `oat config dump --json` - emit merged OAT config with per-key source attribution
|
|
45
46
|
- `oat project status --json` - emit the active project's full parsed control-plane state
|
|
46
47
|
- `oat project list --json` - emit summary state for tracked projects under the configured projects root
|
|
48
|
+
- `oat project complete-state <project-path>` - emit the canonical completed lifecycle shape into a tracked project's `state.md`
|
|
47
49
|
|
|
48
50
|
## Requirements
|
|
49
51
|
|
|
@@ -39,6 +39,7 @@ Notable inspection commands introduced in the current CLI surface:
|
|
|
39
39
|
- `oat config dump --json` - merged config with source attribution
|
|
40
40
|
- `oat project status --json` - full parsed state for the active tracked project
|
|
41
41
|
- `oat project list --json` - summary state for tracked projects under the configured projects root
|
|
42
|
+
- `oat project complete-state <project-path>` - apply the canonical completed-state mutation to a project's `state.md`; used by `oat-project-complete` during lifecycle closeout
|
|
42
43
|
|
|
43
44
|
## `oat config` surface flags
|
|
44
45
|
|
|
@@ -104,7 +104,7 @@ When `autoReviewAtCheckpoints` is enabled (via `.oat/config.json` or `plan.md` f
|
|
|
104
104
|
|
|
105
105
|
### Quick lane diagram
|
|
106
106
|
|
|
107
|
-
1. `oat-project-quick-start` (adaptive discovery —
|
|
107
|
+
1. `oat-project-quick-start` (adaptive discovery — provide a project name and optional description; if only the name is provided, quick-start asks for the missing description before discovery. Well-understood requests synthesize quickly, exploratory requests invest in solution space exploration)
|
|
108
108
|
2. Decision point: straight to plan, optional lightweight `design.md`, or promote to spec-driven
|
|
109
109
|
3. Implement:
|
|
110
110
|
- `oat-project-implement` (sequential)
|
|
@@ -14,7 +14,7 @@ Use this section when you want to choose the right OAT skill for a task. If you
|
|
|
14
14
|
|
|
15
15
|
## Key Skills by Use Case
|
|
16
16
|
|
|
17
|
-
- Start a new tracked project: `oat-project-new` or `oat-project-quick-start`
|
|
17
|
+
- Start a new tracked project: `oat-project-new` or `oat-project-quick-start` (quick start accepts a project name plus optional description; if you omit the description it should ask before discovery begins)
|
|
18
18
|
- Resume an existing project: `oat-project-open` and `oat-project-progress`
|
|
19
19
|
- Execute a ready plan: `oat-project-implement`
|
|
20
20
|
- Import an existing plan: `oat-project-import-plan`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-docs
|
|
3
|
-
version: 1.0.
|
|
3
|
+
version: 1.0.1
|
|
4
4
|
description: Use when a user asks questions about OAT workflows, CLI commands, skill authoring, configuration, or project lifecycle. Answers questions by reading locally-bundled OAT documentation.
|
|
5
5
|
argument-hint: '[question]'
|
|
6
6
|
disable-model-invocation: false
|
|
@@ -161,13 +161,15 @@ Would you like me to:
|
|
|
161
161
|
To create a new OAT project, you have two main approaches:
|
|
162
162
|
|
|
163
163
|
1. **Quick mode** (recommended for most tasks):
|
|
164
|
-
oat-project-quick-start <project-name>
|
|
164
|
+
oat-project-quick-start <project-name> "project description"
|
|
165
165
|
|
|
166
166
|
2. **Spec-driven mode** (for complex features):
|
|
167
167
|
oat-project-new <project-name>
|
|
168
168
|
|
|
169
169
|
Quick mode goes straight from discovery to plan. Spec-driven mode adds
|
|
170
|
-
formal spec and design phases.
|
|
170
|
+
formal spec and design phases. If you invoke quick mode with only a
|
|
171
|
+
project name, it should ask you for the missing project description
|
|
172
|
+
before discovery starts.
|
|
171
173
|
|
|
172
174
|
Both create a project directory under your projects root
|
|
173
175
|
(default: .oat/projects/shared/<project-name>/) with standard artifacts:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-complete
|
|
3
|
-
version: 1.4.
|
|
3
|
+
version: 1.4.1
|
|
4
4
|
description: Use when all implementation work is finished and the project is ready to close. Marks the OAT project lifecycle as complete.
|
|
5
5
|
disable-model-invocation: true
|
|
6
6
|
user-invocable: true
|
|
@@ -254,41 +254,19 @@ Rules:
|
|
|
254
254
|
|
|
255
255
|
### Step 5: Set Lifecycle Complete
|
|
256
256
|
|
|
257
|
-
|
|
257
|
+
Delegate the canonical `state.md` completion mutation to the CLI:
|
|
258
258
|
|
|
259
259
|
```bash
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
# Check if oat_lifecycle already exists
|
|
264
|
-
if grep -q "^oat_lifecycle:" "$STATE_FILE"; then
|
|
265
|
-
# Update existing (portable approach using temp file)
|
|
266
|
-
sed 's/^oat_lifecycle:.*/oat_lifecycle: complete/' "$STATE_FILE" > "$STATE_FILE.tmp"
|
|
267
|
-
mv "$STATE_FILE.tmp" "$STATE_FILE"
|
|
268
|
-
else
|
|
269
|
-
# Add after oat_phase_status line using awk (more portable for multi-line inserts)
|
|
270
|
-
awk '/^oat_phase_status:/ {print; print "oat_lifecycle: complete"; next} 1' "$STATE_FILE" > "$STATE_FILE.tmp"
|
|
271
|
-
mv "$STATE_FILE.tmp" "$STATE_FILE"
|
|
260
|
+
COMPLETE_STATE_ARGS=("$PROJECT_PATH")
|
|
261
|
+
if [[ "$SHOULD_ARCHIVE" == "true" && "$IS_SHARED_PROJECT" == "true" ]]; then
|
|
262
|
+
COMPLETE_STATE_ARGS+=("--archived")
|
|
272
263
|
fi
|
|
273
264
|
|
|
274
|
-
|
|
275
|
-
sed -E "s/^oat_project_completed:.*/oat_project_completed: \"$NOW_UTC\"/" "$STATE_FILE" > "$STATE_FILE.tmp"
|
|
276
|
-
mv "$STATE_FILE.tmp" "$STATE_FILE"
|
|
277
|
-
sed -E "s/^oat_project_state_updated:.*/oat_project_state_updated: \"$NOW_UTC\"/" "$STATE_FILE" > "$STATE_FILE.tmp"
|
|
278
|
-
mv "$STATE_FILE.tmp" "$STATE_FILE"
|
|
265
|
+
oat project complete-state "${COMPLETE_STATE_ARGS[@]}"
|
|
279
266
|
```
|
|
280
267
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
- Set `**Status:** Complete`
|
|
284
|
-
- Set `**Last Updated:**` to the completion date in `YYYY-MM-DD`
|
|
285
|
-
- In `## Current Phase`, replace the body with:
|
|
286
|
-
- `Lifecycle complete; archived locally` when the project is archived in Step 8
|
|
287
|
-
- `Lifecycle complete` when the project is completed without archive
|
|
288
|
-
- In `## Progress`, preserve the existing completed workflow/review bullets and add `- ✓ Project lifecycle complete` if it is not already present
|
|
289
|
-
- In `## Next Milestone`, replace the body with `None. Project complete.`
|
|
290
|
-
|
|
291
|
-
Do not infer these body mutations from other archived projects. Apply them directly as part of this skill.
|
|
268
|
+
The CLI command owns both the frontmatter completion fields and the canonical markdown body updates for `state.md`.
|
|
269
|
+
It must set `oat_lifecycle: complete`, completion timestamps, `**Status:** Complete`, `**Last Updated:**`, the canonical `## Current Phase` body, normalized `## Progress`, and `## Next Milestone`.
|
|
292
270
|
|
|
293
271
|
### Step 6: Clear Active Project Pointer
|
|
294
272
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-project-quick-start
|
|
3
|
-
version: 1.3.
|
|
3
|
+
version: 1.3.3
|
|
4
4
|
description: Use when a task is small enough for quick mode or rapid iteration is preferred. Scaffolds a lightweight OAT project from discovery directly to a runnable plan, with optional brainstorming and lightweight design.
|
|
5
|
-
argument-hint: '<project-name>'
|
|
5
|
+
argument-hint: '<project-name> ["project description"]'
|
|
6
6
|
disable-model-invocation: true
|
|
7
7
|
user-invocable: true
|
|
8
8
|
allowed-tools: Read, Write, Bash, Glob, Grep, AskUserQuestion
|
|
@@ -83,7 +83,11 @@ PROJECTS_ROOT="${PROJECTS_ROOT%/}"
|
|
|
83
83
|
|
|
84
84
|
If no valid active project exists:
|
|
85
85
|
|
|
86
|
-
-
|
|
86
|
+
- Resolve startup input from `$ARGUMENTS` before doing any discovery work:
|
|
87
|
+
- Accept `{project-name}` plus an optional `{project-description}`.
|
|
88
|
+
- If `$ARGUMENTS` contains only a bare `{project-name}` (for example a slug or short title) without a substantive description, ask the user for a short project description before scanning the repo or drafting discovery.
|
|
89
|
+
- Do not infer requirements from the project name alone or go exploring the codebase to guess what the project means.
|
|
90
|
+
- If neither field is available, ask for both the project name and a short project description. One or two sentences is enough for the description.
|
|
87
91
|
- Create project via the same scaffolding path used by `oat-project-new`:
|
|
88
92
|
|
|
89
93
|
```bash
|
|
@@ -116,6 +120,8 @@ If `"$PROJECT_PATH/discovery.md"` is missing, create it from `.oat/templates/dis
|
|
|
116
120
|
|
|
117
121
|
Before asking questions, classify the request:
|
|
118
122
|
|
|
123
|
+
- Base this classification on the user's project description plus session context. A bare project name by itself is not enough context to start discovery.
|
|
124
|
+
|
|
119
125
|
- **Well-understood** — the user has a clear mental model, requirements are specific, approach is obvious. Examples: "add a CLI flag for verbose output", "rename X to Y across the codebase."
|
|
120
126
|
→ Synthesize `discovery.md` from available session context quickly when enough detail is already available. Ask only the minimum additional questions needed to remove blockers for a quality plan.
|
|
121
127
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { readFile as defaultReadFile, writeFile as defaultWriteFile } from 'node:fs/promises';
|
|
2
|
+
import { buildCommandContext, type CommandContext } from '../../../app/command-context.js';
|
|
3
|
+
import { dirExists, fileExists } from '../../../fs/io.js';
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
interface ProjectCompleteStateDependencies {
|
|
6
|
+
buildCommandContext: (options: Parameters<typeof buildCommandContext>[0]) => 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 createProjectCompleteStateCommand(overrides?: Partial<ProjectCompleteStateDependencies>): 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-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;AAE/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;AAsED,wBAAgB,iCAAiC,CAC/C,SAAS,GAAE,OAAO,CAAC,gCAAgC,CAAM,GACxD,OAAO,CA2BT"}
|
|
@@ -0,0 +1,78 @@
|
|
|
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 { readGlobalOptions } from '../../shared/shared.utils.js';
|
|
5
|
+
import { CliError } from '../../../errors/cli-error.js';
|
|
6
|
+
import { dirExists, fileExists } from '../../../fs/io.js';
|
|
7
|
+
import { resolveProjectRoot } from '../../../fs/paths.js';
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
import { renderCompletedProjectState } from './state-utils.js';
|
|
10
|
+
const DEFAULT_DEPENDENCIES = {
|
|
11
|
+
buildCommandContext,
|
|
12
|
+
resolveProjectRoot,
|
|
13
|
+
readFile: defaultReadFile,
|
|
14
|
+
writeFile: defaultWriteFile,
|
|
15
|
+
dirExists,
|
|
16
|
+
fileExists,
|
|
17
|
+
now: () => new Date(),
|
|
18
|
+
};
|
|
19
|
+
function resolveTargetProjectPath(repoRoot, projectPath) {
|
|
20
|
+
return isAbsolute(projectPath) ? projectPath : join(repoRoot, projectPath);
|
|
21
|
+
}
|
|
22
|
+
async function runProjectCompleteState(projectPath, options, context, dependencies) {
|
|
23
|
+
try {
|
|
24
|
+
const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
25
|
+
const targetProjectPath = resolveTargetProjectPath(repoRoot, projectPath);
|
|
26
|
+
if (!(await dependencies.dirExists(targetProjectPath))) {
|
|
27
|
+
throw new CliError(`Project not found: ${projectPath}`, 1);
|
|
28
|
+
}
|
|
29
|
+
const statePath = join(targetProjectPath, 'state.md');
|
|
30
|
+
if (!(await dependencies.fileExists(statePath))) {
|
|
31
|
+
throw new CliError(`Project state.md not found: ${statePath}`, 1);
|
|
32
|
+
}
|
|
33
|
+
const now = dependencies.now();
|
|
34
|
+
const content = await dependencies.readFile(statePath, 'utf8');
|
|
35
|
+
const updatedContent = renderCompletedProjectState(content, {
|
|
36
|
+
archived: options.archived ?? false,
|
|
37
|
+
nowUtc: now.toISOString(),
|
|
38
|
+
today: now.toISOString().slice(0, 10),
|
|
39
|
+
});
|
|
40
|
+
await dependencies.writeFile(statePath, updatedContent, 'utf8');
|
|
41
|
+
if (context.json) {
|
|
42
|
+
context.logger.json({
|
|
43
|
+
status: 'ok',
|
|
44
|
+
projectPath,
|
|
45
|
+
statePath,
|
|
46
|
+
archived: options.archived ?? false,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
context.logger.info(`Updated completed project state: ${projectPath}`);
|
|
51
|
+
}
|
|
52
|
+
process.exitCode = 0;
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
56
|
+
if (context.json) {
|
|
57
|
+
context.logger.json({ status: 'error', message });
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
context.logger.error(message);
|
|
61
|
+
}
|
|
62
|
+
process.exitCode = error instanceof CliError ? error.exitCode : 1;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export function createProjectCompleteStateCommand(overrides = {}) {
|
|
66
|
+
const dependencies = {
|
|
67
|
+
...DEFAULT_DEPENDENCIES,
|
|
68
|
+
...overrides,
|
|
69
|
+
};
|
|
70
|
+
return new Command('complete-state')
|
|
71
|
+
.description('Update a project state.md to the completed lifecycle shape')
|
|
72
|
+
.argument('<project-path>', 'Project path to update')
|
|
73
|
+
.option('--archived', 'Mark the completed project as archived locally')
|
|
74
|
+
.action(async (projectPath, options, command) => {
|
|
75
|
+
const context = dependencies.buildCommandContext(readGlobalOptions(command));
|
|
76
|
+
await runProjectCompleteState(projectPath, options, context, dependencies);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface CompleteProjectStateOptions {
|
|
2
|
+
archived: boolean;
|
|
3
|
+
nowUtc: string;
|
|
4
|
+
today: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function renderCompletedProjectState(content: string, options: CompleteProjectStateOptions): string;
|
|
7
|
+
//# sourceMappingURL=state-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-utils.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/complete-state/state-utils.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAoED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,2BAA2B,GACnC,MAAM,CA8DR"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { getFrontmatterBlock, getFrontmatterField, } from '../../shared/frontmatter.js';
|
|
2
|
+
import { replaceFrontmatter, upsertFrontmatterField, } from '../../shared/frontmatter-write.js';
|
|
3
|
+
function replaceLine(content, pattern, nextLine) {
|
|
4
|
+
return pattern.test(content) ? content.replace(pattern, nextLine) : content;
|
|
5
|
+
}
|
|
6
|
+
function findSectionBounds(content, heading) {
|
|
7
|
+
const marker = `## ${heading}\n\n`;
|
|
8
|
+
const start = content.indexOf(marker);
|
|
9
|
+
if (start === -1) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const bodyStart = start + marker.length;
|
|
13
|
+
const nextHeading = content.indexOf('\n## ', bodyStart);
|
|
14
|
+
return {
|
|
15
|
+
start,
|
|
16
|
+
bodyStart,
|
|
17
|
+
end: nextHeading === -1 ? content.length : nextHeading,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function readSectionBody(content, heading) {
|
|
21
|
+
const bounds = findSectionBounds(content, heading);
|
|
22
|
+
if (!bounds) {
|
|
23
|
+
return '';
|
|
24
|
+
}
|
|
25
|
+
return content.slice(bounds.bodyStart, bounds.end).trim();
|
|
26
|
+
}
|
|
27
|
+
function replaceSection(content, heading, body) {
|
|
28
|
+
const bounds = findSectionBounds(content, heading);
|
|
29
|
+
if (!bounds) {
|
|
30
|
+
return content;
|
|
31
|
+
}
|
|
32
|
+
return [
|
|
33
|
+
content.slice(0, bounds.start),
|
|
34
|
+
`## ${heading}\n\n${body.trim()}\n`,
|
|
35
|
+
content.slice(bounds.end),
|
|
36
|
+
].join('');
|
|
37
|
+
}
|
|
38
|
+
function renderCompletedProgress(content) {
|
|
39
|
+
const existingLines = readSectionBody(content, 'Progress')
|
|
40
|
+
.split('\n')
|
|
41
|
+
.map((line) => line.trim())
|
|
42
|
+
.filter((line) => line.length > 0 && line.startsWith('- ✓'));
|
|
43
|
+
if (!existingLines.includes('- ✓ Project lifecycle complete')) {
|
|
44
|
+
existingLines.push('- ✓ Project lifecycle complete');
|
|
45
|
+
}
|
|
46
|
+
return existingLines.join('\n');
|
|
47
|
+
}
|
|
48
|
+
export function renderCompletedProjectState(content, options) {
|
|
49
|
+
const frontmatter = getFrontmatterBlock(content);
|
|
50
|
+
if (!frontmatter) {
|
|
51
|
+
throw new Error('state.md is missing frontmatter');
|
|
52
|
+
}
|
|
53
|
+
let nextBlock = upsertFrontmatterField(frontmatter, 'oat_lifecycle', 'complete', true).nextBlock;
|
|
54
|
+
nextBlock = upsertFrontmatterField(nextBlock, 'oat_project_completed', `"${options.nowUtc}"`, true).nextBlock;
|
|
55
|
+
nextBlock = upsertFrontmatterField(nextBlock, 'oat_project_state_updated', `"${options.nowUtc}"`, true).nextBlock;
|
|
56
|
+
let nextContent = nextBlock === frontmatter
|
|
57
|
+
? content
|
|
58
|
+
: replaceFrontmatter(content, nextBlock);
|
|
59
|
+
nextContent = replaceLine(nextContent, /^\*\*Status:\*\*.*$/m, '**Status:** Complete');
|
|
60
|
+
nextContent = replaceLine(nextContent, /^\*\*Last Updated:\*\*.*$/m, `**Last Updated:** ${options.today}`);
|
|
61
|
+
const currentPhase = options.archived
|
|
62
|
+
? 'Lifecycle complete; archived locally'
|
|
63
|
+
: 'Lifecycle complete';
|
|
64
|
+
nextContent = replaceSection(nextContent, 'Current Phase', currentPhase);
|
|
65
|
+
nextContent = replaceSection(nextContent, 'Progress', renderCompletedProgress(nextContent));
|
|
66
|
+
nextContent = replaceSection(nextContent, 'Next Milestone', 'None. Project complete.');
|
|
67
|
+
const currentLifecycle = getFrontmatterField(nextBlock, 'oat_lifecycle');
|
|
68
|
+
if (currentLifecycle !== 'complete') {
|
|
69
|
+
throw new Error('Failed to set oat_lifecycle: complete');
|
|
70
|
+
}
|
|
71
|
+
return nextContent;
|
|
72
|
+
}
|
|
@@ -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;AAWpC,wBAAgB,oBAAoB,IAAI,OAAO,CAW9C"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { createProjectArchiveCommand } from './archive/index.js';
|
|
3
|
+
import { createProjectCompleteStateCommand } from './complete-state/index.js';
|
|
3
4
|
import { createProjectListCommand } from './list.js';
|
|
4
5
|
import { createProjectNewCommand } from './new/index.js';
|
|
5
6
|
import { createProjectOpenCommand } from './open/index.js';
|
|
@@ -10,6 +11,7 @@ export function createProjectCommand() {
|
|
|
10
11
|
return new Command('project')
|
|
11
12
|
.description('Manage OAT project workflows')
|
|
12
13
|
.addCommand(createProjectArchiveCommand())
|
|
14
|
+
.addCommand(createProjectCompleteStateCommand())
|
|
13
15
|
.addCommand(createProjectListCommand())
|
|
14
16
|
.addCommand(createProjectNewCommand())
|
|
15
17
|
.addCommand(createProjectOpenCommand())
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/validation/skills.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,uBAAuB;IACtC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,uCAAuC;IACtD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sCAAsC;IACrD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE,KAChD,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B,UAAU,6BAA6B;IACrC,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/validation/skills.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,uBAAuB;IACtC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,uCAAuC;IACtD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sCAAsC;IACrD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE,KAChD,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B,UAAU,6BAA6B;IACrC,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAmPD,wBAAsB,gCAAgC,CACpD,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,uCAAuC,EAChD,YAAY,GAAE,6BAAkC,GAC/C,OAAO,CAAC,sCAAsC,CAAC,CAoBjD;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,wBAA6B,EACtC,YAAY,GAAE,6BAAkC,GAC/C,OAAO,CAAC,uBAAuB,CAAC,CA6HlC"}
|
|
@@ -77,6 +77,15 @@ function validateQuickStartSemantics(skillPath, content, findings) {
|
|
|
77
77
|
message: 'Quick-start must limit follow-up questions to the minimum needed to remove blockers',
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
|
+
if (!(/(project description|project brief)/i.test(content) &&
|
|
81
|
+
/(project name alone|bare .*project-name|only a bare .*project-name)/i.test(content) &&
|
|
82
|
+
/(ask the user|ask for)/i.test(content) &&
|
|
83
|
+
/(do not infer requirements from the project name alone|not enough context to start discovery)/i.test(content))) {
|
|
84
|
+
findings.push({
|
|
85
|
+
file: skillPath,
|
|
86
|
+
message: 'Quick-start must treat a bare project name as insufficient input, ask for a project description, and avoid inferring scope from the repo',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
80
89
|
}
|
|
81
90
|
async function listChangedSkillFiles(repoRoot, baseRef, dependencies) {
|
|
82
91
|
const execFile = dependencies.gitExecFile ?? execFileAsync;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-agent-toolkit/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.34",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Open Agent Toolkit CLI",
|
|
6
6
|
"homepage": "https://github.com/voxmedia/open-agent-toolkit/tree/main/packages/cli",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"ora": "^9.0.0",
|
|
34
34
|
"yaml": "2.8.2",
|
|
35
35
|
"zod": "^3.25.76",
|
|
36
|
-
"@open-agent-toolkit/control-plane": "0.0.
|
|
36
|
+
"@open-agent-toolkit/control-plane": "0.0.34"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/node": "^22.10.0",
|