@open-agent-toolkit/cli 0.2.58 → 0.2.62
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 +27 -4
- package/assets/agents/oat-reviewer.md +25 -14
- package/assets/bundle-metadata.json +1 -1
- package/assets/docs/cli-utilities/configuration.md +16 -0
- package/assets/docs/cli-utilities/workflow-gates.md +91 -6
- package/assets/docs/contributing/skills.md +27 -5
- package/assets/docs/provider-sync/commands.md +23 -0
- package/assets/docs/reference/cli-reference.md +10 -3
- package/assets/docs/reference/oat-directory-structure.md +1 -0
- package/assets/docs/workflows/ideas/index.md +1 -1
- package/assets/docs/workflows/index.md +1 -0
- package/assets/docs/workflows/projects/artifacts.md +24 -3
- package/assets/docs/workflows/projects/autonomy.md +5 -2
- package/assets/docs/workflows/projects/dispatch-ceiling.md +43 -7
- package/assets/docs/workflows/projects/hill-checkpoints.md +21 -0
- package/assets/docs/workflows/projects/implementation-execution.md +10 -2
- package/assets/docs/workflows/projects/lifecycle.md +128 -10
- package/assets/docs/workflows/projects/pr-flow.md +2 -0
- package/assets/docs/workflows/projects/reviews.md +1 -1
- package/assets/docs/workflows/projects/state-machine.md +20 -0
- package/assets/docs/workflows/skills/index.md +2 -1
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-brainstorm/SKILL.md +61 -12
- package/assets/skills/oat-docs/SKILL.md +13 -8
- package/assets/skills/oat-doctor/SKILL.md +3 -3
- package/assets/skills/oat-pjm-review-backlog/SKILL.md +2 -2
- package/assets/skills/oat-project-autonomous/SKILL.md +14 -9
- package/assets/skills/oat-project-autonomous/references/gate-inventory.md +59 -38
- package/assets/skills/oat-project-capture/SKILL.md +2 -2
- package/assets/skills/oat-project-design/SKILL.md +10 -5
- package/assets/skills/oat-project-discover/SKILL.md +15 -9
- package/assets/skills/oat-project-document/SKILL.md +11 -1
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +59 -38
- package/assets/skills/oat-project-implement/SKILL.md +3 -3
- package/assets/skills/oat-project-implement/references/completion-and-closeout.md +149 -24
- package/assets/skills/oat-project-implement/references/dispatch-and-dry-run.md +14 -8
- package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +59 -38
- package/assets/skills/oat-project-implement/references/phase-execution.md +16 -1
- package/assets/skills/oat-project-implement/references/plan-and-resume.md +19 -1
- package/assets/skills/oat-project-import-plan/SKILL.md +75 -6
- package/assets/skills/oat-project-lite/SKILL.md +467 -0
- package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +331 -0
- package/assets/skills/oat-project-next/SKILL.md +54 -11
- package/assets/skills/oat-project-plan/SKILL.md +42 -5
- package/assets/skills/oat-project-plan-writing/SKILL.md +100 -3
- package/assets/skills/oat-project-pr-final/SKILL.md +33 -7
- package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +59 -38
- package/assets/skills/oat-project-pr-progress/SKILL.md +3 -3
- package/assets/skills/oat-project-progress/SKILL.md +27 -3
- package/assets/skills/oat-project-promote-spec-driven/SKILL.md +3 -1
- package/assets/skills/oat-project-quick-start/SKILL.md +29 -4
- package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +59 -38
- package/assets/skills/oat-project-review-provide/SKILL.md +37 -11
- package/assets/skills/oat-project-review-provide-remote/SKILL.md +12 -5
- package/assets/skills/oat-project-summary/SKILL.md +27 -3
- package/assets/templates/plan-lite.md +165 -0
- package/assets/templates/plan.md +1 -1
- package/assets/templates/state.md +5 -2
- package/dist/commands/gate/index.d.ts.map +1 -1
- package/dist/commands/gate/index.js +102 -8
- package/dist/commands/init/index.d.ts.map +1 -1
- package/dist/commands/init/index.js +16 -1
- package/dist/commands/project/dispatch-ceiling/index.d.ts.map +1 -1
- package/dist/commands/project/dispatch-ceiling/index.js +10 -1
- package/dist/commands/project/index.d.ts.map +1 -1
- package/dist/commands/project/index.js +2 -0
- package/dist/commands/project/new/index.d.ts +3 -2
- package/dist/commands/project/new/index.d.ts.map +1 -1
- package/dist/commands/project/new/index.js +2 -1
- package/dist/commands/project/new/scaffold.d.ts +5 -3
- package/dist/commands/project/new/scaffold.d.ts.map +1 -1
- package/dist/commands/project/new/scaffold.js +38 -10
- package/dist/commands/project/promote/index.d.ts +2 -0
- package/dist/commands/project/promote/index.d.ts.map +1 -0
- package/dist/commands/project/promote/index.js +1 -0
- package/dist/commands/project/promote/promote.d.ts +47 -0
- package/dist/commands/project/promote/promote.d.ts.map +1 -0
- package/dist/commands/project/promote/promote.js +322 -0
- package/dist/commands/project/split/run.d.ts.map +1 -1
- package/dist/commands/project/split/run.js +8 -1
- package/dist/commands/project/validate-plan/index.d.ts.map +1 -1
- package/dist/commands/project/validate-plan/index.js +25 -1
- package/dist/commands/project/validate-plan/validate-plan.d.ts +8 -0
- package/dist/commands/project/validate-plan/validate-plan.d.ts.map +1 -1
- package/dist/commands/project/validate-plan/validate-plan.js +49 -0
- package/dist/commands/remove/skill/remove-skill.d.ts.map +1 -1
- package/dist/commands/remove/skill/remove-skill.js +10 -1
- package/dist/commands/shared/frontmatter.d.ts +32 -1
- package/dist/commands/shared/frontmatter.d.ts.map +1 -1
- package/dist/commands/shared/frontmatter.js +93 -0
- package/dist/commands/state/generate.d.ts.map +1 -1
- package/dist/commands/state/generate.js +23 -0
- package/dist/commands/status/index.d.ts.map +1 -1
- package/dist/commands/status/index.js +8 -1
- package/dist/commands/sync/apply.d.ts.map +1 -1
- package/dist/commands/sync/apply.js +40 -6
- package/dist/commands/sync/index.d.ts.map +1 -1
- package/dist/commands/sync/index.js +11 -17
- package/dist/commands/sync/sync.types.d.ts +6 -6
- package/dist/commands/sync/sync.types.d.ts.map +1 -1
- package/dist/commands/tools/shared/pack-manifest.d.ts.map +1 -1
- package/dist/commands/tools/shared/pack-manifest.js +2 -0
- package/dist/config/resolve.d.ts +16 -0
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +16 -8
- package/dist/engine/execute-plan.d.ts.map +1 -1
- package/dist/engine/execute-plan.js +6 -0
- package/dist/manifest/index.d.ts +2 -1
- package/dist/manifest/index.d.ts.map +1 -1
- package/dist/manifest/index.js +1 -1
- package/dist/manifest/manager.d.ts +40 -0
- package/dist/manifest/manager.d.ts.map +1 -1
- package/dist/manifest/manager.js +35 -0
- package/package.json +2 -2
|
@@ -63,6 +63,9 @@ async function recordDetectedRecommendation(repoRoot, document, dependencies) {
|
|
|
63
63
|
throw new Error('Cannot record detected split recommendation without an active project');
|
|
64
64
|
}
|
|
65
65
|
const discoveryPath = join(repoRoot, localConfig.activeProject, 'discovery.md');
|
|
66
|
+
if (!(await exists(discoveryPath, dependencies))) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
66
69
|
await dependencies.appendFile(discoveryPath, [
|
|
67
70
|
'',
|
|
68
71
|
'## Detected Split Recommendation',
|
|
@@ -74,6 +77,7 @@ async function recordDetectedRecommendation(repoRoot, document, dependencies) {
|
|
|
74
77
|
.join(', ')}`,
|
|
75
78
|
'',
|
|
76
79
|
].join('\n'), 'utf8');
|
|
80
|
+
return true;
|
|
77
81
|
}
|
|
78
82
|
function isEffectivelyNonInteractive(options, context, processEnv) {
|
|
79
83
|
return (options.nonInteractive === true ||
|
|
@@ -180,7 +184,10 @@ export function createProjectSplitRunCommand(overrides = {}) {
|
|
|
180
184
|
if (isEffectivelyNonInteractive(options, context, dependencies.processEnv) &&
|
|
181
185
|
(document.origin === 'detected-mid-stream' ||
|
|
182
186
|
document.origin === 'detected-convergence')) {
|
|
183
|
-
await recordDetectedRecommendation(repoRoot, document, dependencies);
|
|
187
|
+
const recorded = await recordDetectedRecommendation(repoRoot, document, dependencies);
|
|
188
|
+
if (!recorded) {
|
|
189
|
+
context.logger.info('skipped split recommendation: no discovery.md for this project');
|
|
190
|
+
}
|
|
184
191
|
context.logger.error('Detected split requires interactive confirmation; recommendation recorded.');
|
|
185
192
|
process.exitCode = 1;
|
|
186
193
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/validate-plan/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/validate-plan/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,UAAU,+BAA+B;IACvC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;CACjE;AAMD,wBAAgB,gCAAgC,CAC9C,SAAS,GAAE,OAAO,CAAC,+BAA+B,CAAM,GACvD,OAAO,CAsGT"}
|
|
@@ -3,7 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { buildCommandContext, } from '../../../app/command-context.js';
|
|
4
4
|
import { readGlobalOptions } from '../../shared/shared.utils.js';
|
|
5
5
|
import { Command } from 'commander';
|
|
6
|
-
import { extractPhaseIdsFromPlan, parseFrontmatterFromContent, validateParallelGroups, } from './validate-plan.js';
|
|
6
|
+
import { extractPhaseIdsFromPlan, parseFrontmatterFromContent, validateLitePlan, validateParallelGroups, } from './validate-plan.js';
|
|
7
7
|
const DEFAULT_DEPENDENCIES = {
|
|
8
8
|
buildCommandContext,
|
|
9
9
|
};
|
|
@@ -47,6 +47,30 @@ export function createProjectValidatePlanCommand(overrides = {}) {
|
|
|
47
47
|
}
|
|
48
48
|
const groups = frontmatterResult.data['oat_plan_parallel_groups'];
|
|
49
49
|
const phaseIds = extractPhaseIdsFromPlan(content);
|
|
50
|
+
let workflowMode = null;
|
|
51
|
+
try {
|
|
52
|
+
const stateContent = readFileSync(join(options.projectPath, 'state.md'), 'utf-8');
|
|
53
|
+
const stateFrontmatter = parseFrontmatterFromContent(stateContent);
|
|
54
|
+
const mode = stateFrontmatter.kind === 'invalid'
|
|
55
|
+
? null
|
|
56
|
+
: stateFrontmatter.data['oat_workflow_mode'];
|
|
57
|
+
workflowMode = typeof mode === 'string' ? mode : null;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
workflowMode = null;
|
|
61
|
+
}
|
|
62
|
+
const liteResult = validateLitePlan(content, workflowMode);
|
|
63
|
+
if (!liteResult.ok) {
|
|
64
|
+
if (context.json) {
|
|
65
|
+
context.logger.json({ valid: false, errors: [liteResult.message] });
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
context.logger.error('Plan validation failed:');
|
|
69
|
+
context.logger.error(` - ${liteResult.message}`);
|
|
70
|
+
}
|
|
71
|
+
process.exitCode = 1;
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
50
74
|
const result = validateParallelGroups(groups, phaseIds);
|
|
51
75
|
if (result.valid) {
|
|
52
76
|
if (context.json) {
|
|
@@ -15,6 +15,14 @@ export type ValidationResult = {
|
|
|
15
15
|
valid: false;
|
|
16
16
|
errors: string[];
|
|
17
17
|
};
|
|
18
|
+
export type LitePlanValidationResult = {
|
|
19
|
+
ok: true;
|
|
20
|
+
} | {
|
|
21
|
+
ok: false;
|
|
22
|
+
code: 'lite-multi-phase' | 'lite-parallel-groups' | 'lite-criterion-without-command';
|
|
23
|
+
message: string;
|
|
24
|
+
};
|
|
25
|
+
export declare function validateLitePlan(planContent: string, workflowMode: string | null | undefined): LitePlanValidationResult;
|
|
18
26
|
export declare function validateParallelGroups(groups: unknown, phaseIds: readonly string[]): ValidationResult;
|
|
19
27
|
export declare function extractPhaseIdsFromPlan(planContent: string): string[];
|
|
20
28
|
//# sourceMappingURL=validate-plan.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate-plan.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/validate-plan/validate-plan.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,GACd,iBAAiB,CAyBnB;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GACf;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEvC,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,gBAAgB,CAgDlB;AAED,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAOrE"}
|
|
1
|
+
{"version":3,"file":"validate-plan.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/validate-plan/validate-plan.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,GACd,iBAAiB,CAyBnB;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GACf;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEvC,MAAM,MAAM,wBAAwB,GAChC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IACE,EAAE,EAAE,KAAK,CAAC;IACV,IAAI,EACA,kBAAkB,GAClB,sBAAsB,GACtB,gCAAgC,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAeN,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACtC,wBAAwB,CA8C1B;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,gBAAgB,CAgDlB;AAED,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAOrE"}
|
|
@@ -25,6 +25,55 @@ export function parseFrontmatterFromContent(content) {
|
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
+
function validationCriteria(planContent) {
|
|
29
|
+
const heading = /^## Validation Criteria[ \t]*$/m.exec(planContent);
|
|
30
|
+
if (!heading)
|
|
31
|
+
return null;
|
|
32
|
+
const bodyStart = heading.index + heading[0].length;
|
|
33
|
+
const remaining = planContent.slice(bodyStart);
|
|
34
|
+
const nextHeading = /^##\s+/m.exec(remaining);
|
|
35
|
+
const body = remaining.slice(0, nextHeading?.index ?? remaining.length);
|
|
36
|
+
return body
|
|
37
|
+
.split('\n')
|
|
38
|
+
.filter((line) => /^\s*-\s+/.test(line))
|
|
39
|
+
.map((line) => line.replace(/^\s*-\s+(?:\[[ xX]\]\s*)?/, '').trim());
|
|
40
|
+
}
|
|
41
|
+
export function validateLitePlan(planContent, workflowMode) {
|
|
42
|
+
if (workflowMode !== 'lite') {
|
|
43
|
+
return { ok: true };
|
|
44
|
+
}
|
|
45
|
+
const phaseCount = planContent.match(/^## Phase\b.*$/gm)?.length ?? 0;
|
|
46
|
+
if (phaseCount !== 1) {
|
|
47
|
+
return {
|
|
48
|
+
ok: false,
|
|
49
|
+
code: 'lite-multi-phase',
|
|
50
|
+
message: `Lite plans must contain exactly one phase; found ${phaseCount}.`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const frontmatter = parseFrontmatterFromContent(planContent);
|
|
54
|
+
const groups = frontmatter.kind === 'invalid'
|
|
55
|
+
? undefined
|
|
56
|
+
: frontmatter.data['oat_plan_parallel_groups'];
|
|
57
|
+
if (groups !== undefined &&
|
|
58
|
+
groups !== null &&
|
|
59
|
+
!(Array.isArray(groups) && groups.length === 0)) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
code: 'lite-parallel-groups',
|
|
63
|
+
message: 'Lite plans must declare no parallel groups.',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const criteria = validationCriteria(planContent);
|
|
67
|
+
const invalidCriterion = criteria?.find((criterion) => !criterion.startsWith('manual:') && !/`[^`\n]+`/.test(criterion));
|
|
68
|
+
if (!criteria || criteria.length === 0 || invalidCriterion !== undefined) {
|
|
69
|
+
return {
|
|
70
|
+
ok: false,
|
|
71
|
+
code: 'lite-criterion-without-command',
|
|
72
|
+
message: 'Every lite Validation Criteria bullet must name a command in backticks or start with manual: after the bullet marker.',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return { ok: true };
|
|
76
|
+
}
|
|
28
77
|
export function validateParallelGroups(groups, phaseIds) {
|
|
29
78
|
// Missing or empty → valid (sequential execution, no parallelism declared)
|
|
30
79
|
if (groups === undefined || groups === null) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remove-skill.d.ts","sourceRoot":"","sources":["../../../../src/commands/remove/skill/remove-skill.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EACL,iBAAiB,EAElB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAC;AAGvB,OAAO,
|
|
1
|
+
{"version":3,"file":"remove-skill.d.ts","sourceRoot":"","sources":["../../../../src/commands/remove/skill/remove-skill.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EACL,iBAAiB,EAElB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAC;AAGvB,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,aAAa,EAKnB,MAAM,iBAAiB,CAAC;AAMzB,OAAO,EACL,KAAK,yBAAyB,EAG9B,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEtE,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqCpC,MAAM,WAAW,uBAAuB;IACtC,mBAAmB,EAAE,CACnB,OAAO,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,KAC1C,cAAc,CAAC;IACpB,gBAAgB,EAAE,CAChB,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,cAAc,KACpB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1D,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,cAAc,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5D,WAAW,EAAE,MAAM,eAAe,EAAE,CAAC;IACrC,sBAAsB,EAAE,CACtB,QAAQ,EAAE,eAAe,EAAE,EAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,KACf,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACxC,eAAe,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,KAAK,KAAK,WAAW,EAAE,CAAC;IAC3E,kBAAkB,EAAE,CAClB,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE,KAAK,KACT,cAAc,EAAE,CAAC;IACtB,iCAAiC,EAAE,CACjC,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,MAAM,KACd,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACpD,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClD;AAED,wBAAgB,oCAAoC,IAAI,uBAAuB,CA0C9E;AAiPD,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,OAAO,EACf,YAAY,EAAE,uBAAuB,GACpC,OAAO,CAAC,OAAO,CAAC,CA2DlB;AAED,wBAAgB,wBAAwB,CACtC,SAAS,GAAE,OAAO,CAAC,uBAAuB,CAAM,GAC/C,OAAO,CAwCT"}
|
|
@@ -7,7 +7,7 @@ import { DEFAULT_SYNC_CONFIG, loadSyncConfig, } from '../../../config/sync-confi
|
|
|
7
7
|
import { classifyObsoleteMappingRetirement, } from '../../../engine/index.js';
|
|
8
8
|
import { dirExists, fileExists } from '../../../fs/io.js';
|
|
9
9
|
import { resolveProjectRoot, resolveScopeRoot, toPosixPath } from '../../../fs/paths.js';
|
|
10
|
-
import { loadManifest, removeEntry, saveManifest, } from '../../../manifest/index.js';
|
|
10
|
+
import { detectManifestVersionRestamp, formatManifestVersionRestampWarning, loadManifest, removeEntry, saveManifest, } from '../../../manifest/index.js';
|
|
11
11
|
import { claudeAdapter } from '../../../providers/claude/index.js';
|
|
12
12
|
import { codexAdapter } from '../../../providers/codex/index.js';
|
|
13
13
|
import { copilotAdapter } from '../../../providers/copilot/index.js';
|
|
@@ -179,6 +179,7 @@ async function buildScopePlan(scope, scopeRoot, skillName, dependencies) {
|
|
|
179
179
|
managedProviderViews: dedupeViews(managedProviderViews),
|
|
180
180
|
unmanagedProviderViews: dedupeViews(unmanagedProviderViews),
|
|
181
181
|
manifestProvidersToRemove: [...manifestProvidersToRemove],
|
|
182
|
+
versionRestamp: detectManifestVersionRestamp(scope, manifest),
|
|
182
183
|
};
|
|
183
184
|
}
|
|
184
185
|
function logDryRun(context, plan) {
|
|
@@ -217,6 +218,9 @@ async function applyPlan(context, plan, dependencies) {
|
|
|
217
218
|
for (const provider of plan.manifestProvidersToRemove) {
|
|
218
219
|
nextManifest = removeEntry(nextManifest, plan.canonicalRelativePath, provider);
|
|
219
220
|
}
|
|
221
|
+
if (plan.versionRestamp && !context.json) {
|
|
222
|
+
context.logger.warn(formatManifestVersionRestampWarning('remove skill', plan.versionRestamp));
|
|
223
|
+
}
|
|
220
224
|
await dependencies.saveManifest(plan.manifestPath, nextManifest);
|
|
221
225
|
context.logger.info(`[apply][${plan.scope}] removed ${plan.canonicalRelativePath}`);
|
|
222
226
|
if (plan.unmanagedProviderViews.length > 0) {
|
|
@@ -267,6 +271,11 @@ export async function runRemoveSkill(context, skillName, dryRun, dependencies) {
|
|
|
267
271
|
status: 'removed',
|
|
268
272
|
skill: skillName,
|
|
269
273
|
scopes: toJsonScopeResults(plans),
|
|
274
|
+
// Applied restamps only. The dry-run payload deliberately omits this
|
|
275
|
+
// field rather than naming a restamp that no save will perform.
|
|
276
|
+
manifestVersionRestamps: plans
|
|
277
|
+
.map((plan) => plan.versionRestamp)
|
|
278
|
+
.filter((restamp) => restamp !== undefined),
|
|
270
279
|
});
|
|
271
280
|
}
|
|
272
281
|
return true;
|
|
@@ -1,12 +1,43 @@
|
|
|
1
1
|
export declare const PROJECT_STATE_KINDS: readonly ['implementation', 'coordination'];
|
|
2
2
|
export declare const PROJECT_STATE_PHASES: readonly ['discovery', 'spec', 'design', 'plan', 'implement', 'decomposition'];
|
|
3
|
-
export declare const PROJECT_STATE_FRONTMATTER_FIELDS: readonly ['oat_kind', 'oat_parent', 'oat_siblings', 'oat_depends_on', 'oat_children', 'oat_inherited_context_revalidated', 'oat_phase', 'oat_phase_status', 'oat_status', 'oat_workflow_mode', 'oat_lifecycle', 'oat_current_task', 'oat_last_commit', 'oat_blockers', 'oat_hill_checkpoints', 'oat_hill_completed', 'oat_parallel_execution', 'oat_implement_exit_gate', 'oat_pr_status', 'oat_pr_url', 'oat_project_created', 'oat_project_completed', 'oat_project_state_updated', 'oat_docs_updated', 'oat_generated', 'oat_template', 'oat_template_name'];
|
|
3
|
+
export declare const PROJECT_STATE_FRONTMATTER_FIELDS: readonly ['oat_kind', 'oat_parent', 'oat_siblings', 'oat_depends_on', 'oat_children', 'oat_inherited_context_revalidated', 'oat_phase', 'oat_phase_status', 'oat_status', 'oat_workflow_mode', 'oat_lifecycle', 'oat_current_task', 'oat_last_commit', 'oat_blockers', 'oat_hill_checkpoints', 'oat_hill_completed', 'oat_parallel_execution', 'oat_implement_exit_gate', 'oat_skill_gate_overrides', 'oat_pr_status', 'oat_pr_url', 'oat_project_created', 'oat_project_completed', 'oat_project_state_updated', 'oat_docs_updated', 'oat_generated', 'oat_template', 'oat_template_name'];
|
|
4
4
|
export type ProjectStateKind = (typeof PROJECT_STATE_KINDS)[number];
|
|
5
5
|
export type ProjectStatePhase = (typeof PROJECT_STATE_PHASES)[number];
|
|
6
6
|
export type ProjectStateFrontmatterField = (typeof PROJECT_STATE_FRONTMATTER_FIELDS)[number];
|
|
7
7
|
export declare function isProjectStateKind(value: string): value is ProjectStateKind;
|
|
8
8
|
export declare function isProjectStatePhase(value: string): value is ProjectStatePhase;
|
|
9
9
|
export declare function isProjectStateFrontmatterField(value: string): value is ProjectStateFrontmatterField;
|
|
10
|
+
export declare const SKILL_GATE_OVERRIDE_FIELD = "oat_skill_gate_overrides";
|
|
11
|
+
export declare const SKILL_GATE_OVERRIDE_DISABLED = "disabled";
|
|
12
|
+
export declare const SKILL_GATE_OVERRIDE_SOURCE = "state.md:oat_skill_gate_overrides";
|
|
13
|
+
/**
|
|
14
|
+
* Canonical gate-aware lifecycle skills: exactly the skills declaring
|
|
15
|
+
* `oat_gateable: true` in their frontmatter, which is the only set a project
|
|
16
|
+
* override may target. An override key outside this set can never disable
|
|
17
|
+
* anything, so accepting one would silently record an inert instruction.
|
|
18
|
+
*
|
|
19
|
+
* This set does not bound which skills a configured gate may target. Gate
|
|
20
|
+
* resolution performs the same config lookup for any skill name, so a
|
|
21
|
+
* configured gate on a non-gate-aware skill still resolves and executes; it
|
|
22
|
+
* simply applies to every project because no override key for it is accepted.
|
|
23
|
+
*
|
|
24
|
+
* `skills.test.ts` pins this constant against the live `oat_gateable: true`
|
|
25
|
+
* declarations so the two cannot drift apart.
|
|
26
|
+
*/
|
|
27
|
+
export declare const GATE_AWARE_SKILLS: readonly ['oat-project-implement', 'oat-project-import-plan', 'oat-project-lite', 'oat-project-plan', 'oat-project-quick-start'];
|
|
28
|
+
export type SkillGateOverrideValue = typeof SKILL_GATE_OVERRIDE_DISABLED;
|
|
29
|
+
export interface ProjectSkillGateOverrides {
|
|
30
|
+
/** False when the key is absent entirely: absence means follow configuration. */
|
|
31
|
+
present: boolean;
|
|
32
|
+
overrides: Record<string, SkillGateOverrideValue>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Strict parser for the per-project gate override map.
|
|
36
|
+
*
|
|
37
|
+
* Absence is not an error and never fabricates configuration. Every rejection
|
|
38
|
+
* names the offending project state path so the operator can repair it.
|
|
39
|
+
*/
|
|
40
|
+
export declare function parseSkillGateOverrides(frontmatter: string, statePath: string): ProjectSkillGateOverrides;
|
|
10
41
|
export declare function getFrontmatterBlock(content: string): string | null;
|
|
11
42
|
export declare function getFrontmatterField(frontmatter: string, field: string): string | null;
|
|
12
43
|
export declare function parseFrontmatterScalarFields(frontmatter: string, fields: readonly string[]): {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../../src/commands/shared/frontmatter.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,YAAI,gBAAgB,EAAE,cAAc,CAAU,CAAC;AAE/E,eAAO,MAAM,oBAAoB,YAC/B,WAAW,EACX,MAAM,EACN,QAAQ,EACR,MAAM,EACN,WAAW,EACX,eAAe,CACP,CAAC;AAEX,eAAO,MAAM,gCAAgC,YAC3C,UAAU,EACV,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,mCAAmC,EACnC,WAAW,EACX,kBAAkB,EAClB,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,sBAAsB,EACtB,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,EACzB,eAAe,EACf,YAAY,EACZ,qBAAqB,EACrB,uBAAuB,EACvB,2BAA2B,EAC3B,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,mBAAmB,CACX,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,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,SAAS,MAAM,EAAE,GACxB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CA4BpD;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"}
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../../src/commands/shared/frontmatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -29,6 +29,7 @@ export const PROJECT_STATE_FRONTMATTER_FIELDS = [
|
|
|
29
29
|
'oat_hill_completed',
|
|
30
30
|
'oat_parallel_execution',
|
|
31
31
|
'oat_implement_exit_gate',
|
|
32
|
+
'oat_skill_gate_overrides',
|
|
32
33
|
'oat_pr_status',
|
|
33
34
|
'oat_pr_url',
|
|
34
35
|
'oat_project_created',
|
|
@@ -48,6 +49,98 @@ export function isProjectStatePhase(value) {
|
|
|
48
49
|
export function isProjectStateFrontmatterField(value) {
|
|
49
50
|
return PROJECT_STATE_FRONTMATTER_FIELDS.includes(value);
|
|
50
51
|
}
|
|
52
|
+
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
53
|
+
export const SKILL_GATE_OVERRIDE_FIELD = 'oat_skill_gate_overrides';
|
|
54
|
+
export const SKILL_GATE_OVERRIDE_DISABLED = 'disabled';
|
|
55
|
+
export const SKILL_GATE_OVERRIDE_SOURCE = `state.md:${SKILL_GATE_OVERRIDE_FIELD}`;
|
|
56
|
+
/**
|
|
57
|
+
* Canonical gate-aware lifecycle skills: exactly the skills declaring
|
|
58
|
+
* `oat_gateable: true` in their frontmatter, which is the only set a project
|
|
59
|
+
* override may target. An override key outside this set can never disable
|
|
60
|
+
* anything, so accepting one would silently record an inert instruction.
|
|
61
|
+
*
|
|
62
|
+
* This set does not bound which skills a configured gate may target. Gate
|
|
63
|
+
* resolution performs the same config lookup for any skill name, so a
|
|
64
|
+
* configured gate on a non-gate-aware skill still resolves and executes; it
|
|
65
|
+
* simply applies to every project because no override key for it is accepted.
|
|
66
|
+
*
|
|
67
|
+
* `skills.test.ts` pins this constant against the live `oat_gateable: true`
|
|
68
|
+
* declarations so the two cannot drift apart.
|
|
69
|
+
*/
|
|
70
|
+
export const GATE_AWARE_SKILLS = [
|
|
71
|
+
'oat-project-implement',
|
|
72
|
+
'oat-project-import-plan',
|
|
73
|
+
'oat-project-lite',
|
|
74
|
+
'oat-project-plan',
|
|
75
|
+
'oat-project-quick-start',
|
|
76
|
+
];
|
|
77
|
+
function skillGateOverrideError(statePath, detail) {
|
|
78
|
+
return new Error(`${statePath}: \`${SKILL_GATE_OVERRIDE_FIELD}\` ${detail}. Use a map of gate-aware skill names to the literal value \`${SKILL_GATE_OVERRIDE_DISABLED}\`, or remove the key to follow configured gates.`);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Strict parser for the per-project gate override map.
|
|
82
|
+
*
|
|
83
|
+
* Absence is not an error and never fabricates configuration. Every rejection
|
|
84
|
+
* names the offending project state path so the operator can repair it.
|
|
85
|
+
*/
|
|
86
|
+
export function parseSkillGateOverrides(frontmatter, statePath) {
|
|
87
|
+
const document = YAML.parseDocument(frontmatter, { uniqueKeys: true });
|
|
88
|
+
if (document.errors.length > 0) {
|
|
89
|
+
throw skillGateOverrideError(statePath, `cannot be read because the frontmatter is malformed (${document.errors[0]?.message ?? 'YAML parse error'})`);
|
|
90
|
+
}
|
|
91
|
+
// A scalar or sequence root is malformed project state, not "no overrides":
|
|
92
|
+
// returning an empty map here would silently launch a disabled gate.
|
|
93
|
+
if (!isMap(document.contents)) {
|
|
94
|
+
throw skillGateOverrideError(statePath, 'cannot be read because the frontmatter root is not a YAML map');
|
|
95
|
+
}
|
|
96
|
+
const matches = document.contents.items.filter((pair) => isScalar(pair.key) && pair.key.value === SKILL_GATE_OVERRIDE_FIELD);
|
|
97
|
+
if (matches.length === 0) {
|
|
98
|
+
return { present: false, overrides: {} };
|
|
99
|
+
}
|
|
100
|
+
// `uniqueKeys` already rejects a duplicate top-level key above; this stays as
|
|
101
|
+
// a fail-closed guard rather than silently reading the first of several.
|
|
102
|
+
if (matches.length > 1) {
|
|
103
|
+
throw skillGateOverrideError(statePath, 'is declared more than once');
|
|
104
|
+
}
|
|
105
|
+
const value = matches[0]?.value;
|
|
106
|
+
// An explicitly null or empty map is a deliberate "no overrides" statement.
|
|
107
|
+
if (value === null || (isScalar(value) && value.value === null)) {
|
|
108
|
+
return { present: true, overrides: {} };
|
|
109
|
+
}
|
|
110
|
+
if (!isMap(value)) {
|
|
111
|
+
throw skillGateOverrideError(statePath, 'must be a map of skill names to `disabled`');
|
|
112
|
+
}
|
|
113
|
+
const overrides = {};
|
|
114
|
+
for (const pair of value.items) {
|
|
115
|
+
if (!isScalar(pair.key) || typeof pair.key.value !== 'string') {
|
|
116
|
+
throw skillGateOverrideError(statePath, 'has a non-string skill key');
|
|
117
|
+
}
|
|
118
|
+
// Exact spelling only: a padded or decorated key is not the skill name.
|
|
119
|
+
const skill = pair.key.value;
|
|
120
|
+
if (!skill) {
|
|
121
|
+
throw skillGateOverrideError(statePath, 'has an empty skill key');
|
|
122
|
+
}
|
|
123
|
+
if (pair.key.anchor !== undefined || pair.key.tag !== undefined) {
|
|
124
|
+
throw skillGateOverrideError(statePath, `decorates the key \`${skill}\` with a YAML anchor or tag`);
|
|
125
|
+
}
|
|
126
|
+
if (!GATE_AWARE_SKILLS.includes(skill)) {
|
|
127
|
+
throw skillGateOverrideError(statePath, `names \`${skill}\`, which is not a gate-aware skill`);
|
|
128
|
+
}
|
|
129
|
+
if (hasOwnProperty.call(overrides, skill)) {
|
|
130
|
+
throw skillGateOverrideError(statePath, `declares \`${skill}\` more than once`);
|
|
131
|
+
}
|
|
132
|
+
const entry = pair.value;
|
|
133
|
+
if (!isScalar(entry) ||
|
|
134
|
+
entry.anchor !== undefined ||
|
|
135
|
+
entry.tag !== undefined ||
|
|
136
|
+
typeof entry.value !== 'string' ||
|
|
137
|
+
entry.value !== SKILL_GATE_OVERRIDE_DISABLED) {
|
|
138
|
+
throw skillGateOverrideError(statePath, `sets \`${skill}\` to an unsupported value`);
|
|
139
|
+
}
|
|
140
|
+
overrides[skill] = SKILL_GATE_OVERRIDE_DISABLED;
|
|
141
|
+
}
|
|
142
|
+
return { present: true, overrides };
|
|
143
|
+
}
|
|
51
144
|
export function getFrontmatterBlock(content) {
|
|
52
145
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
53
146
|
return match?.[1] ?? null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/commands/state/generate.ts"],"names":[],"mappings":"AAQA,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAU9E,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CAClD;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/commands/state/generate.ts"],"names":[],"mappings":"AAQA,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAU9E,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CAClD;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAkHD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvE;AAgiBD,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CAkF9B"}
|
|
@@ -88,6 +88,8 @@ async function readProjectState(repoRoot, projectPath) {
|
|
|
88
88
|
const stateFile = join(repoRoot, projectPath, 'state.md');
|
|
89
89
|
const phase = (await parseFrontmatterField(stateFile, 'oat_phase')) || 'unknown';
|
|
90
90
|
const phaseStatus = (await parseFrontmatterField(stateFile, 'oat_phase_status')) || 'unknown';
|
|
91
|
+
const readyForRaw = await parseFrontmatterField(stateFile, 'oat_ready_for');
|
|
92
|
+
const readyFor = readyForRaw && readyForRaw !== 'null' ? readyForRaw : '';
|
|
91
93
|
let currentTask = await parseFrontmatterField(stateFile, 'oat_current_task');
|
|
92
94
|
if (!currentTask || currentTask === 'null')
|
|
93
95
|
currentTask = '-';
|
|
@@ -115,6 +117,7 @@ async function readProjectState(repoRoot, projectPath) {
|
|
|
115
117
|
return {
|
|
116
118
|
phase,
|
|
117
119
|
phaseStatus,
|
|
120
|
+
readyFor,
|
|
118
121
|
currentTask,
|
|
119
122
|
lifecycle,
|
|
120
123
|
pauseTimestamp,
|
|
@@ -230,6 +233,15 @@ function computeNextStep(project, hasProjects, state) {
|
|
|
230
233
|
reason: `Complete ${state.phase} HiLL approval before advancing`,
|
|
231
234
|
};
|
|
232
235
|
}
|
|
236
|
+
if (state.workflowMode === 'quick' &&
|
|
237
|
+
state.phase === 'discovery' &&
|
|
238
|
+
state.phaseStatus === 'complete' &&
|
|
239
|
+
state.readyFor === 'oat-project-quick-start') {
|
|
240
|
+
return {
|
|
241
|
+
step: 'oat-project-quick-start',
|
|
242
|
+
reason: 'Continue the promoted quick workflow',
|
|
243
|
+
};
|
|
244
|
+
}
|
|
233
245
|
// Workflow mode routing
|
|
234
246
|
const key = `${state.workflowMode}:${state.phase}:${state.phaseStatus}`;
|
|
235
247
|
const routeMap = {
|
|
@@ -271,6 +283,10 @@ function computeNextStep(project, hasProjects, state) {
|
|
|
271
283
|
step: 'oat-project-import-plan',
|
|
272
284
|
reason: 'Continue import-plan normalization',
|
|
273
285
|
},
|
|
286
|
+
'lite:plan:in_progress': {
|
|
287
|
+
step: 'oat-project-lite',
|
|
288
|
+
reason: 'Continue lite planning',
|
|
289
|
+
},
|
|
274
290
|
};
|
|
275
291
|
if (routeMap[key])
|
|
276
292
|
return routeMap[key];
|
|
@@ -298,6 +314,12 @@ function computeNextStep(project, hasProjects, state) {
|
|
|
298
314
|
return sharedMap[sharedKey];
|
|
299
315
|
// Implementation complete — recommend docs sync if not yet done, then PR
|
|
300
316
|
if (state.phase === 'implement' && state.phaseStatus === 'complete') {
|
|
317
|
+
if (state.workflowMode === 'lite') {
|
|
318
|
+
return {
|
|
319
|
+
step: 'oat-project-pr-final',
|
|
320
|
+
reason: 'Generate final PR description from plan and implementation',
|
|
321
|
+
};
|
|
322
|
+
}
|
|
301
323
|
if (!state.docsUpdated || state.docsUpdated === '') {
|
|
302
324
|
return {
|
|
303
325
|
step: 'oat-project-document',
|
|
@@ -469,6 +491,7 @@ function buildDashboardMarkdown(project, state, knowledge, staleness, nextStep,
|
|
|
469
491
|
lines.push('- `oat-project-new` - Create a spec-driven project');
|
|
470
492
|
lines.push('- `oat-project-quick-start` - Create a quick workflow project');
|
|
471
493
|
lines.push('- `oat-project-import-plan` - Import an external provider plan');
|
|
494
|
+
lines.push('- `oat-project-lite` - Create a lite workflow project');
|
|
472
495
|
lines.push('- `oat project open <name>` - Open or resume a project');
|
|
473
496
|
lines.push('- `oat project pause [name]` - Pause active or named project');
|
|
474
497
|
lines.push('- `oat-project-complete` - Mark project complete');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/status/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,yBAAyB,EAC/B,MAAM,wBAAwB,CAAC;AAMhC,OAAO,EACL,KAAK,cAAc,EAIpB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAIL,KAAK,sBAAsB,EAC5B,MAAM,2CAA2C,CAAC;AAEnD,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,YAAY,EAGlB,MAAM,iCAAiC,CAAC;AAWzC,OAAO,EAIL,KAAK,kBAAkB,EAEvB,KAAK,aAAa,EAEnB,MAAM,uCAAuC,CAAC;AAU/C,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,WAAW,EAIjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,cAAc,EAGnB,KAAK,+BAA+B,EAIrC,MAAM,eAAe,CAAC;AAOvB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/status/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@ import { detectDrift, detectStrays, filterKnownStrays, } from '../../drift/index
|
|
|
17
17
|
import { HOOK_DRIFT_WARNING, HOOK_STRAY_INFO, mergeUserScopeMaterializationEntries, scanBundledManagedAgents, scanCanonical, } from '../../engine/index.js';
|
|
18
18
|
import { resolveAssetsRoot } from '../../fs/assets.js';
|
|
19
19
|
import { normalizeToPosixPath, resolveProjectRoot, resolveScopeRoot, } from '../../fs/paths.js';
|
|
20
|
-
import { loadManifest, saveManifest } from '../../manifest/manager.js';
|
|
20
|
+
import { detectManifestVersionRestamp, formatManifestVersionRestampWarning, loadManifest, saveManifest, } from '../../manifest/manager.js';
|
|
21
21
|
import { applyCodexProjectExtensionPlan, computeCodexProjectExtensionPlan, } from '../../providers/codex/codec/sync-extension.js';
|
|
22
22
|
import { applyCursorProjectExtensionPlan, computeCursorProjectExtensionPlan, } from '../../providers/cursor/codec/sync-extension.js';
|
|
23
23
|
import { getConfigAwareAdapters, getProviderRegistrations, getSyncMappings, resolveProviderScopeContext, } from '../../providers/shared/index.js';
|
|
@@ -651,6 +651,7 @@ async function collectScopeReports(scope, context, dependencies) {
|
|
|
651
651
|
activeAdapterNames,
|
|
652
652
|
userAgentMaterializationCoverage: scope === 'user' ? agentCoverage : 'none',
|
|
653
653
|
providerContext,
|
|
654
|
+
versionRestamp: detectManifestVersionRestamp(scope, manifest),
|
|
654
655
|
};
|
|
655
656
|
}
|
|
656
657
|
async function runStatusCommand(context, dependencies, options = {}) {
|
|
@@ -844,6 +845,12 @@ async function runStatusCommand(context, dependencies, options = {}) {
|
|
|
844
845
|
}
|
|
845
846
|
}
|
|
846
847
|
if (manifestChanged) {
|
|
848
|
+
// Placed after the collection-migration block and immediately before
|
|
849
|
+
// the only status-owned save. An aborted migration never reaches
|
|
850
|
+
// here, so it never claims a restamp it did not perform.
|
|
851
|
+
if (scopeCollection.versionRestamp && !context.json) {
|
|
852
|
+
context.logger.warn(formatManifestVersionRestampWarning('status', scopeCollection.versionRestamp));
|
|
853
|
+
}
|
|
847
854
|
await dependencies.saveManifest(scopeCollection.manifestPath, scopeCollection.manifest);
|
|
848
855
|
}
|
|
849
856
|
if (adoptedCount > 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAiB3D,OAAO,KAAK,EACV,aAAa,EACb,uBAAuB,EAExB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAiB3D,OAAO,KAAK,EACV,aAAa,EACb,uBAAuB,EAExB,MAAM,cAAc,CAAC;AAgVtB,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,aAAa,EAAE,EAC3B,YAAY,EAAE,uBAAuB,GACpC,OAAO,CAAC,IAAI,CAAC,CAoMf"}
|
|
@@ -126,13 +126,26 @@ function coreHumanStatus(status) {
|
|
|
126
126
|
return 'unknown';
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
-
|
|
129
|
+
/** The sentence `formatSyncPlan` appends to its heading for an empty plan. */
|
|
130
|
+
const EMPTY_PLAN_SUFFIX = '\nNo changes required.';
|
|
131
|
+
function formatCoreResults(plan, evidence, dependencies, restampOnly) {
|
|
130
132
|
const operations = [...plan.entries, ...plan.removals];
|
|
131
133
|
if (operations.length === 0) {
|
|
132
134
|
if ((plan.collections?.length ?? 0) > 0) {
|
|
133
135
|
return 'Core results\nNo per-entry operations.';
|
|
134
136
|
}
|
|
135
|
-
|
|
137
|
+
const planOutput = dependencies.formatSyncPlan(plan, true);
|
|
138
|
+
if (!restampOnly || !planOutput.endsWith(EMPTY_PLAN_SUFFIX)) {
|
|
139
|
+
return planOutput;
|
|
140
|
+
}
|
|
141
|
+
// `formatSyncPlan` appends "No changes required." to its heading for any
|
|
142
|
+
// empty plan, and it is shared with dry-run and other callers, so it stays
|
|
143
|
+
// untouched. On the restamp-only path that sentence would contradict the
|
|
144
|
+
// trailing message two lines later, so the command layer drops exactly that
|
|
145
|
+
// known suffix and lets the trailing message be the run's single claim.
|
|
146
|
+
// Removing only a matching suffix, rather than keeping the first line,
|
|
147
|
+
// means an injected formatter's other content is never truncated.
|
|
148
|
+
return planOutput.slice(0, -EMPTY_PLAN_SUFFIX.length);
|
|
136
149
|
}
|
|
137
150
|
const resultsByIdentity = new Map((evidence?.operationResults ?? []).map((result) => [
|
|
138
151
|
syncOperationIdentity(result),
|
|
@@ -155,7 +168,12 @@ function formatCoreResults(plan, evidence, dependencies) {
|
|
|
155
168
|
: '';
|
|
156
169
|
return `Core results${aggregate}\n${lines.join('\n')}`;
|
|
157
170
|
}
|
|
158
|
-
function formatAppliedOutput(scopePlans, coreApplyEvidence, dependencies
|
|
171
|
+
function formatAppliedOutput(scopePlans, coreApplyEvidence, dependencies,
|
|
172
|
+
// True when the run planned no operation at all and the manifest restamp is
|
|
173
|
+
// the only mutation. It is a whole-run state, matching the single trailing
|
|
174
|
+
// summary message, so with `--scope all` every scope's body is empty and at
|
|
175
|
+
// least one of them was restamped.
|
|
176
|
+
restampOnly) {
|
|
159
177
|
if (scopePlans.length === 0) {
|
|
160
178
|
return dependencies.formatSyncPlan({
|
|
161
179
|
scope: 'project',
|
|
@@ -165,7 +183,7 @@ function formatAppliedOutput(scopePlans, coreApplyEvidence, dependencies) {
|
|
|
165
183
|
}
|
|
166
184
|
return scopePlans
|
|
167
185
|
.map((scopePlan) => {
|
|
168
|
-
const syncOutput = formatCoreResults(scopePlan.plan, coreApplyEvidence.find((evidence) => evidence.plan === scopePlan.plan), dependencies);
|
|
186
|
+
const syncOutput = formatCoreResults(scopePlan.plan, coreApplyEvidence.find((evidence) => evidence.plan === scopePlan.plan), dependencies, restampOnly);
|
|
169
187
|
const collectionOutput = formatCollectionLifecycle(buildCollectionLifecycle(scopePlan, coreApplyEvidence.find((evidence) => evidence.plan === scopePlan.plan)
|
|
170
188
|
?.collectionResults));
|
|
171
189
|
if (scopePlan.materializationExtensions.length === 0) {
|
|
@@ -310,9 +328,25 @@ export async function runSyncApply(context, scopePlans, dependencies) {
|
|
|
310
328
|
});
|
|
311
329
|
}
|
|
312
330
|
else {
|
|
313
|
-
|
|
331
|
+
// A restamp is a real mutation: it overwrites the producing-version
|
|
332
|
+
// evidence even though no file operation was planned. Reporting "no
|
|
333
|
+
// changes required" for that case would contradict the advisory this same
|
|
334
|
+
// run just emitted, so the state is resolved once and threaded through
|
|
335
|
+
// both the plan body and the trailing message.
|
|
336
|
+
//
|
|
337
|
+
// `failed === 0` is load-bearing rather than defensive: a rejected
|
|
338
|
+
// collection is counted as a failure but is not a *planned* operation
|
|
339
|
+
// (`countPlannedOperations` admits only the mutating collection actions),
|
|
340
|
+
// so a run can fail with `plannedOperations === 0`. That run is not
|
|
341
|
+
// restamp-only and must never be described as needing no content changes.
|
|
342
|
+
const restampOnly = summary.plannedOperations === 0 &&
|
|
343
|
+
summary.failed === 0 &&
|
|
344
|
+
versionSkew.length > 0;
|
|
345
|
+
context.logger.info(formatAppliedOutput(scopePlans, coreApplyEvidence, dependencies, restampOnly));
|
|
314
346
|
if (summary.plannedOperations === 0) {
|
|
315
|
-
context.logger.info(
|
|
347
|
+
context.logger.info(restampOnly
|
|
348
|
+
? '\nManifest version refreshed; no content changes required.'
|
|
349
|
+
: '\nNo changes required.');
|
|
316
350
|
}
|
|
317
351
|
else if (summary.failed > 0) {
|
|
318
352
|
context.logger.warn('\nSync completed with partial failures.');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAGL,KAAK,UAAU,EAEhB,MAAM,eAAe,CAAC;AAWvB,OAAO,EAOL,KAAK,oBAAoB,EAC1B,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAGL,KAAK,UAAU,EAEhB,MAAM,eAAe,CAAC;AAWvB,OAAO,EAOL,KAAK,oBAAoB,EAC1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAI5C,OAAO,KAAK,EACV,aAAa,EAEb,uBAAuB,EAGxB,MAAM,cAAc,CAAC;AAEtB,KAAK,0BAA0B,GAAG,IAAI,CACpC,uBAAuB,EACvB,iBAAiB,GAAG,eAAe,CACpC,GAAG;IACF,aAAa,EAAE,CACb,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,aAAa,EACpB,OAAO,CAAC,EAAE,SAAS,mBAAmB,EAAE,KACrC,UAAU,CAAC,uBAAuB,CAAC,eAAe,CAAC,CAAC,CAAC;IAC1D,eAAe,EAAE,CACf,IAAI,EAAE,UAAU,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;QAChE,sCAAsC,CAAC,EAAE,QAAQ,CAC/C,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAClC,CAAC;KACH,KACE,UAAU,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC5D,2BAA2B,CAAC,EAAE,CAAC,KAAK,EAAE;QACpC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;QAC9B,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,UAAU,CAAC;KACpB,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;CACrC,CAAC;AA2fF,wBAAgB,iBAAiB,CAC/B,SAAS,GAAE,OAAO,CAAC,0BAA0B,CAAM,GAClD,OAAO,CA+DT"}
|