@juancr11/sibu 0.6.0 → 0.8.0
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/bin/admin/changelog.js +155 -0
- package/bin/admin/release.js +217 -0
- package/bin/entrypoints/cli/create-program.js +1 -1
- package/bin/entrypoints/cli/execute-command.js +6 -6
- package/bin/modules/interactive-guidance/index.js +1 -0
- package/bin/{shared → modules/interactive-guidance}/prompts.js +17 -1
- package/bin/modules/maintainer-release-support/generate-changelog/changelog-format.js +213 -0
- package/bin/modules/maintainer-release-support/generate-changelog/changelog-writer.js +91 -0
- package/bin/modules/maintainer-release-support/generate-changelog/git-history.js +93 -0
- package/bin/modules/maintainer-release-support/generate-changelog/handler.js +167 -0
- package/bin/modules/maintainer-release-support/generate-changelog/semver.js +40 -0
- package/bin/modules/maintainer-release-support/index.js +2 -0
- package/bin/modules/maintainer-release-support/release-workflow/git-release.js +114 -0
- package/bin/modules/maintainer-release-support/release-workflow/handler.js +369 -0
- package/bin/modules/maintainer-release-support/release-workflow/package-json.js +181 -0
- package/bin/modules/maintainer-release-support/release-workflow/release-plan.js +87 -0
- package/bin/{features/init-project → modules/project-adoption}/handler.js +7 -5
- package/bin/modules/project-adoption/index.js +1 -0
- package/bin/modules/skill-selection-management/index.js +3 -0
- package/bin/{features → modules/skill-selection-management}/list-skills/handler.js +14 -4
- package/bin/{features → modules/skill-selection-management}/stop-managing-file/handler.js +15 -8
- package/bin/modules/skill-selection-management/use-skill/command.js +1 -0
- package/bin/{features → modules/skill-selection-management}/use-skill/handler.js +42 -8
- package/bin/{features/sync-project → modules/sync-review}/apply-action.js +5 -3
- package/bin/modules/sync-review/command.js +1 -0
- package/bin/{features/sync-project → modules/sync-review}/handler.js +4 -4
- package/bin/modules/sync-review/index.js +5 -0
- package/bin/{shared → modules/sync-review}/sync-preview.js +11 -7
- package/bin/modules/template-catalog-rendering/index.js +1 -0
- package/bin/modules/template-catalog-rendering/templates.js +60 -0
- package/bin/modules/version-advisory/index.js +1 -0
- package/bin/{shared → modules/version-advisory}/npm-version.js +29 -2
- package/bin/modules/workflow-health-diagnosis/command.js +1 -0
- package/bin/{features/doctor-project → modules/workflow-health-diagnosis}/handler.js +13 -7
- package/bin/modules/workflow-health-diagnosis/index.js +1 -0
- package/bin/modules/workflow-mutation-readiness/index.js +1 -0
- package/bin/{shared → modules/workflow-mutation-readiness}/workflow-mutation-readiness.js +3 -3
- package/bin/modules/workflow-state-registry/index.js +1 -0
- package/bin/{shared → modules/workflow-state-registry}/state.js +3 -1
- package/bin/modules/workflow-target-planning/catalog.js +252 -0
- package/bin/modules/workflow-target-planning/index.js +2 -0
- package/bin/modules/workflow-target-planning/workflow-targets.js +130 -0
- package/bin/shared/catalog.js +0 -253
- package/bin/shared/paths.js +1 -12
- package/bin/shared/workflow-targets.js +3 -2
- package/package.json +4 -2
- package/templates/AGENTS.md +3 -3
- package/templates/manifest.json +38 -27
- package/templates/skills/ai-implementation-plan-executor/SKILL.md +74 -70
- package/templates/skills/ai-implementation-planner/SKILL.md +24 -17
- package/templates/skills/architecture/command-pattern/SKILL.md +32 -20
- package/templates/skills/architecture/ddd-hexagonal/SKILL.md +14 -9
- package/templates/skills/deep-module-map-writer/SKILL.md +241 -0
- package/templates/skills/feature-brief-writer/SKILL.md +24 -24
- package/templates/skills/postgresql-expert/SKILL.md +72 -0
- package/templates/skills/product-vision-writer/SKILL.md +2 -2
- package/templates/skills/scrum-master-planner/SKILL.md +2 -2
- package/templates/skills/technical-design-writer/SKILL.md +15 -15
- package/templates/skills/ux-expert/SKILL.md +1 -1
- package/bin/features/sync-project/preview.js +0 -1
- package/templates/skills/product-context-map-writer/SKILL.md +0 -211
- /package/bin/{features/doctor-project/command.js → modules/cli-command-surface/index.js} +0 -0
- /package/bin/{features/init-project → modules/maintainer-release-support/generate-changelog}/command.js +0 -0
- /package/bin/{features/list-skills → modules/maintainer-release-support/release-workflow}/command.js +0 -0
- /package/bin/{features/stop-managing-file → modules/project-adoption}/command.js +0 -0
- /package/bin/{features/sync-project → modules/skill-selection-management/list-skills}/command.js +0 -0
- /package/bin/{features/use-skill → modules/skill-selection-management/stop-managing-file}/command.js +0 -0
- /package/bin/{features/sync-project → modules/sync-review}/action-prompt.js +0 -0
- /package/bin/{features/sync-project → modules/sync-review}/log-preview.js +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { intro, log, outro } from '@clack/prompts';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import { SELECTABLE_ARCHITECTURE_SKILLS, SELECTABLE_FRAMEWORK_SKILLS, SELECTABLE_LANGUAGE_SKILLS, SELECTABLE_WORKFLOW_SKILLS } from '../../
|
|
4
|
-
import { getProjectContext } from '
|
|
5
|
-
import { renderIntro } from '../../
|
|
6
|
-
import { readStateForDoctor } from '../../
|
|
3
|
+
import { SELECTABLE_ARCHITECTURE_SKILLS, SELECTABLE_DATABASE_SKILLS, SELECTABLE_FRAMEWORK_SKILLS, SELECTABLE_LANGUAGE_SKILLS, SELECTABLE_WORKFLOW_SKILLS } from '../../workflow-target-planning/index.js';
|
|
4
|
+
import { getProjectContext } from '../../../shared/paths.js';
|
|
5
|
+
import { renderIntro } from '../../interactive-guidance/index.js';
|
|
6
|
+
import { readStateForDoctor } from '../../workflow-state-registry/index.js';
|
|
7
7
|
export async function handleListSkills(_command) {
|
|
8
8
|
await renderIntro();
|
|
9
9
|
intro(chalk.cyan('Available workflow skills'));
|
|
@@ -16,6 +16,7 @@ export async function handleListSkills(_command) {
|
|
|
16
16
|
}
|
|
17
17
|
logSkillGroup('Languages', getLanguageSkillItems(state));
|
|
18
18
|
logSkillGroup('Frameworks', getFrameworkSkillItems(state));
|
|
19
|
+
logSkillGroup('Databases', getDatabaseSkillItems(state));
|
|
19
20
|
logSkillGroup('Architecture', getArchitectureSkillItems(state));
|
|
20
21
|
logSkillGroup('Workflow', getWorkflowSkillItems(state));
|
|
21
22
|
outro(chalk.green('Skill list ready.'));
|
|
@@ -38,6 +39,15 @@ function getFrameworkSkillItems(state) {
|
|
|
38
39
|
selected: selectedSkillIds.has(skill.id),
|
|
39
40
|
}));
|
|
40
41
|
}
|
|
42
|
+
function getDatabaseSkillItems(state) {
|
|
43
|
+
const selectedSkillIds = new Set(state?.selectedDatabaseSkills ?? []);
|
|
44
|
+
return SELECTABLE_DATABASE_SKILLS.map((skill) => ({
|
|
45
|
+
name: skill.name,
|
|
46
|
+
id: skill.id,
|
|
47
|
+
description: skill.description,
|
|
48
|
+
selected: selectedSkillIds.has(skill.id),
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
41
51
|
function getArchitectureSkillItems(state) {
|
|
42
52
|
return SELECTABLE_ARCHITECTURE_SKILLS.map((skill) => ({
|
|
43
53
|
name: skill.name,
|
|
@@ -2,14 +2,15 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { cancel, intro, isCancel, log, outro, select } from '@clack/prompts';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
-
import { STATE_RELATIVE_PATH
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
5
|
+
import { STATE_RELATIVE_PATH } from '../../../shared/catalog.js';
|
|
6
|
+
import { resolveSelectableSkillById } from '../../workflow-target-planning/index.js';
|
|
7
|
+
import { readFileHashIfPresent, sha256 } from '../../../shared/hash.js';
|
|
8
|
+
import { getProjectContext } from '../../../shared/paths.js';
|
|
9
|
+
import { renderIntro } from '../../interactive-guidance/index.js';
|
|
10
|
+
import { cloneState, readStateForDoctor, writeStateFile } from '../../workflow-state-registry/index.js';
|
|
11
|
+
import { getTemplateVersion, readTemplateManifest, renderTemplateForSync } from '../../template-catalog-rendering/index.js';
|
|
12
|
+
import { removeUndefinedFields } from '../../../shared/object.js';
|
|
13
|
+
import { getSelectedAgentsFromState, getSelectedArchitectureSkillFromState, getSelectedDatabaseSkillsFromState, getSelectedFrameworkSkillsFromState, getSelectedLanguageSkillsFromState, getSelectedWorkflowSkillsFromState, } from '../../workflow-target-planning/index.js';
|
|
13
14
|
export async function handleStopManagingFile({ skillName }) {
|
|
14
15
|
await renderIntro();
|
|
15
16
|
intro(chalk.cyan('Updating skill management'));
|
|
@@ -109,6 +110,8 @@ function isSkillSelected(state, resolved) {
|
|
|
109
110
|
return state.selectedFrameworkSkills?.includes(resolved.skill.id) ?? false;
|
|
110
111
|
case 'architecture':
|
|
111
112
|
return state.selectedArchitectureSkill === resolved.skill.id;
|
|
113
|
+
case 'database':
|
|
114
|
+
return state.selectedDatabaseSkills?.includes(resolved.skill.id) ?? false;
|
|
112
115
|
case 'workflow':
|
|
113
116
|
return state.selectedWorkflowSkills?.includes(resolved.skill.id) ?? false;
|
|
114
117
|
}
|
|
@@ -124,6 +127,9 @@ function removeSelectedSkill(state, resolved) {
|
|
|
124
127
|
case 'architecture':
|
|
125
128
|
delete state.selectedArchitectureSkill;
|
|
126
129
|
return;
|
|
130
|
+
case 'database':
|
|
131
|
+
state.selectedDatabaseSkills = (state.selectedDatabaseSkills ?? []).filter((skillId) => skillId !== resolved.skill.id);
|
|
132
|
+
return;
|
|
127
133
|
case 'workflow':
|
|
128
134
|
state.selectedWorkflowSkills = (state.selectedWorkflowSkills ?? []).filter((skillId) => skillId !== resolved.skill.id);
|
|
129
135
|
return;
|
|
@@ -167,6 +173,7 @@ function getAgentsUpdate(rootPath, state) {
|
|
|
167
173
|
selectedFrameworkSkills: getSelectedFrameworkSkillsFromState(state),
|
|
168
174
|
selectedArchitectureSkill: getSelectedArchitectureSkillFromState(state),
|
|
169
175
|
selectedWorkflowSkills: getSelectedWorkflowSkillsFromState(state),
|
|
176
|
+
selectedDatabaseSkills: getSelectedDatabaseSkillsFromState(state),
|
|
170
177
|
}),
|
|
171
178
|
};
|
|
172
179
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { log } from '@clack/prompts';
|
|
4
|
-
import { STATE_RELATIVE_PATH
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
4
|
+
import { STATE_RELATIVE_PATH } from '../../../shared/catalog.js';
|
|
5
|
+
import { resolveSelectableSkillById } from '../../workflow-target-planning/index.js';
|
|
6
|
+
import { sha256 } from '../../../shared/hash.js';
|
|
7
|
+
import { getProjectContext } from '../../../shared/paths.js';
|
|
8
|
+
import { renderTemplateForSync } from '../../template-catalog-rendering/index.js';
|
|
9
|
+
import { getWorkflowMutationReadiness } from '../../workflow-mutation-readiness/index.js';
|
|
10
|
+
import { getSelectedAgentsFromState, getWorkflowTargets, renderMissingWorkflowFiles, writeSibuState } from '../../workflow-target-planning/index.js';
|
|
10
11
|
export async function handleUseSkill(command) {
|
|
11
12
|
const { rootPath, statePath } = getProjectContext();
|
|
12
13
|
const readiness = getWorkflowMutationReadiness({ rootPath, statePath });
|
|
@@ -45,6 +46,7 @@ export function getNextSkillSelection(state, skillName) {
|
|
|
45
46
|
const selectedLanguageSkills = [...(state.selectedLanguageSkills ?? [])];
|
|
46
47
|
const selectedFrameworkSkills = [...(state.selectedFrameworkSkills ?? [])];
|
|
47
48
|
const selectedWorkflowSkills = [...(state.selectedWorkflowSkills ?? [])];
|
|
49
|
+
const selectedDatabaseSkills = [...(state.selectedDatabaseSkills ?? [])];
|
|
48
50
|
switch (resolution.resolved.kind) {
|
|
49
51
|
case 'language':
|
|
50
52
|
if (selectedLanguageSkills.includes(resolution.resolved.skill.id)) {
|
|
@@ -58,6 +60,7 @@ export function getNextSkillSelection(state, skillName) {
|
|
|
58
60
|
selectedFrameworkSkills: selectedFrameworkSkills.map(getFrameworkSkillById),
|
|
59
61
|
selectedArchitectureSkill: getArchitectureSkillById(state.selectedArchitectureSkill),
|
|
60
62
|
selectedWorkflowSkills: selectedWorkflowSkills.map(getWorkflowSkillById),
|
|
63
|
+
selectedDatabaseSkills: selectedDatabaseSkills.map(getDatabaseSkillById),
|
|
61
64
|
},
|
|
62
65
|
};
|
|
63
66
|
case 'framework':
|
|
@@ -72,6 +75,7 @@ export function getNextSkillSelection(state, skillName) {
|
|
|
72
75
|
selectedFrameworkSkills: [...selectedFrameworkSkills, resolution.resolved.skill.id].map(getFrameworkSkillById),
|
|
73
76
|
selectedArchitectureSkill: getArchitectureSkillById(state.selectedArchitectureSkill),
|
|
74
77
|
selectedWorkflowSkills: selectedWorkflowSkills.map(getWorkflowSkillById),
|
|
78
|
+
selectedDatabaseSkills: selectedDatabaseSkills.map(getDatabaseSkillById),
|
|
75
79
|
},
|
|
76
80
|
};
|
|
77
81
|
case 'architecture':
|
|
@@ -93,6 +97,22 @@ export function getNextSkillSelection(state, skillName) {
|
|
|
93
97
|
selectedFrameworkSkills: selectedFrameworkSkills.map(getFrameworkSkillById),
|
|
94
98
|
selectedArchitectureSkill: resolution.resolved.skill,
|
|
95
99
|
selectedWorkflowSkills: selectedWorkflowSkills.map(getWorkflowSkillById),
|
|
100
|
+
selectedDatabaseSkills: selectedDatabaseSkills.map(getDatabaseSkillById),
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
case 'database':
|
|
104
|
+
if (selectedDatabaseSkills.includes(resolution.resolved.skill.id)) {
|
|
105
|
+
return { status: 'noop', message: `${resolution.resolved.skill.name} is already selected.` };
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
status: 'selected',
|
|
109
|
+
skillName: resolution.resolved.skill.name,
|
|
110
|
+
selection: {
|
|
111
|
+
selectedLanguageSkills: selectedLanguageSkills.map(getLanguageSkillById),
|
|
112
|
+
selectedFrameworkSkills: selectedFrameworkSkills.map(getFrameworkSkillById),
|
|
113
|
+
selectedArchitectureSkill: getArchitectureSkillById(state.selectedArchitectureSkill),
|
|
114
|
+
selectedWorkflowSkills: selectedWorkflowSkills.map(getWorkflowSkillById),
|
|
115
|
+
selectedDatabaseSkills: [...selectedDatabaseSkills, resolution.resolved.skill.id].map(getDatabaseSkillById),
|
|
96
116
|
},
|
|
97
117
|
};
|
|
98
118
|
case 'workflow':
|
|
@@ -107,6 +127,7 @@ export function getNextSkillSelection(state, skillName) {
|
|
|
107
127
|
selectedFrameworkSkills: selectedFrameworkSkills.map(getFrameworkSkillById),
|
|
108
128
|
selectedArchitectureSkill: getArchitectureSkillById(state.selectedArchitectureSkill),
|
|
109
129
|
selectedWorkflowSkills: [...selectedWorkflowSkills, resolution.resolved.skill.id].map(getWorkflowSkillById),
|
|
130
|
+
selectedDatabaseSkills: selectedDatabaseSkills.map(getDatabaseSkillById),
|
|
110
131
|
},
|
|
111
132
|
};
|
|
112
133
|
}
|
|
@@ -127,12 +148,14 @@ function applySelectedSkill({ rootPath, statePath, state, selectionResult, }) {
|
|
|
127
148
|
selectedFrameworkSkills: selectionResult.selection.selectedFrameworkSkills,
|
|
128
149
|
selectedArchitectureSkill: selectionResult.selection.selectedArchitectureSkill,
|
|
129
150
|
selectedWorkflowSkills: selectionResult.selection.selectedWorkflowSkills,
|
|
151
|
+
selectedDatabaseSkills: selectionResult.selection.selectedDatabaseSkills,
|
|
130
152
|
});
|
|
131
153
|
const [newSkillFile] = renderMissingWorkflowFiles({
|
|
132
154
|
missingTargets: [plan.newSkillTarget],
|
|
133
155
|
selectedLanguageSkills: selectionResult.selection.selectedLanguageSkills,
|
|
134
156
|
selectedFrameworkSkills: selectionResult.selection.selectedFrameworkSkills,
|
|
135
157
|
selectedArchitectureSkill: selectionResult.selection.selectedArchitectureSkill,
|
|
158
|
+
selectedDatabaseSkills: selectionResult.selection.selectedDatabaseSkills,
|
|
136
159
|
});
|
|
137
160
|
fs.mkdirSync(path.dirname(newSkillFile.targetPath), { recursive: true });
|
|
138
161
|
fs.writeFileSync(newSkillFile.targetPath, newSkillFile.contents, { encoding: 'utf8', flag: 'wx' });
|
|
@@ -147,6 +170,7 @@ function applySelectedSkill({ rootPath, statePath, state, selectionResult, }) {
|
|
|
147
170
|
selectedFrameworkSkills: selectionResult.selection.selectedFrameworkSkills,
|
|
148
171
|
selectedArchitectureSkill: selectionResult.selection.selectedArchitectureSkill,
|
|
149
172
|
selectedWorkflowSkills: selectionResult.selection.selectedWorkflowSkills,
|
|
173
|
+
selectedDatabaseSkills: selectionResult.selection.selectedDatabaseSkills,
|
|
150
174
|
targets: plan.targets,
|
|
151
175
|
});
|
|
152
176
|
log.success(`Updated ${STATE_RELATIVE_PATH}`);
|
|
@@ -154,8 +178,8 @@ function applySelectedSkill({ rootPath, statePath, state, selectionResult, }) {
|
|
|
154
178
|
}
|
|
155
179
|
function buildSkillApplicationPlan({ rootPath, state, selectionResult, }) {
|
|
156
180
|
const selectedAgents = getSelectedAgentsFromState(state);
|
|
157
|
-
const previousTargets = getWorkflowTargets(rootPath, selectedAgents, getSelectedLanguageSkillsFromState(state), getSelectedFrameworkSkillsFromState(state), getArchitectureSkillById(state.selectedArchitectureSkill), getSelectedWorkflowSkillsFromState(state));
|
|
158
|
-
const targets = getWorkflowTargets(rootPath, selectedAgents, selectionResult.selection.selectedLanguageSkills, selectionResult.selection.selectedFrameworkSkills, selectionResult.selection.selectedArchitectureSkill, selectionResult.selection.selectedWorkflowSkills);
|
|
181
|
+
const previousTargets = getWorkflowTargets(rootPath, selectedAgents, getSelectedLanguageSkillsFromState(state), getSelectedFrameworkSkillsFromState(state), getArchitectureSkillById(state.selectedArchitectureSkill), getSelectedWorkflowSkillsFromState(state), getSelectedDatabaseSkillsFromState(state));
|
|
182
|
+
const targets = getWorkflowTargets(rootPath, selectedAgents, selectionResult.selection.selectedLanguageSkills, selectionResult.selection.selectedFrameworkSkills, selectionResult.selection.selectedArchitectureSkill, selectionResult.selection.selectedWorkflowSkills, selectionResult.selection.selectedDatabaseSkills);
|
|
159
183
|
const previousTargetPaths = new Set(previousTargets.map((target) => target.targetPath));
|
|
160
184
|
const newSkillTarget = targets.find((target) => !previousTargetPaths.has(target.targetPath));
|
|
161
185
|
const agentsTarget = targets.find((target) => target.label === 'AGENTS.md');
|
|
@@ -194,6 +218,9 @@ function getSelectedFrameworkSkillsFromState(state) {
|
|
|
194
218
|
function getSelectedWorkflowSkillsFromState(state) {
|
|
195
219
|
return (state.selectedWorkflowSkills ?? []).map(getWorkflowSkillById);
|
|
196
220
|
}
|
|
221
|
+
function getSelectedDatabaseSkillsFromState(state) {
|
|
222
|
+
return (state.selectedDatabaseSkills ?? []).map(getDatabaseSkillById);
|
|
223
|
+
}
|
|
197
224
|
function getLanguageSkillById(skillId) {
|
|
198
225
|
const resolution = resolveSelectableSkillById(skillId);
|
|
199
226
|
if (!resolution.ok || resolution.resolved.kind !== 'language') {
|
|
@@ -225,3 +252,10 @@ function getWorkflowSkillById(skillId) {
|
|
|
225
252
|
}
|
|
226
253
|
return resolution.resolved.skill;
|
|
227
254
|
}
|
|
255
|
+
function getDatabaseSkillById(skillId) {
|
|
256
|
+
const resolution = resolveSelectableSkillById(skillId);
|
|
257
|
+
if (!resolution.ok || resolution.resolved.kind !== 'database') {
|
|
258
|
+
throw new Error(`Unsupported database skill in state: ${skillId}`);
|
|
259
|
+
}
|
|
260
|
+
return resolution.resolved.skill;
|
|
261
|
+
}
|
|
@@ -3,9 +3,9 @@ import path from 'node:path';
|
|
|
3
3
|
import { log } from '@clack/prompts';
|
|
4
4
|
import { sha256 } from '../../shared/hash.js';
|
|
5
5
|
import { getSideTemplatePath } from '../../shared/paths.js';
|
|
6
|
-
import { cloneState } from '
|
|
7
|
-
import { getTemplateVersion, renderTemplateForSync } from '
|
|
8
|
-
import { getSelectedArchitectureSkillFromState, getSelectedFrameworkSkillsFromState, getSelectedLanguageSkillsFromState, getSelectedWorkflowSkillsFromState, } from '
|
|
6
|
+
import { cloneState } from '../workflow-state-registry/index.js';
|
|
7
|
+
import { getTemplateVersion, renderTemplateForSync } from '../template-catalog-rendering/index.js';
|
|
8
|
+
import { getSelectedArchitectureSkillFromState, getSelectedDatabaseSkillsFromState, getSelectedFrameworkSkillsFromState, getSelectedLanguageSkillsFromState, getSelectedWorkflowSkillsFromState, } from '../workflow-target-planning/index.js';
|
|
9
9
|
export function applySyncAction({ rootPath, state, manifest, preview, action, }) {
|
|
10
10
|
const nextState = cloneState(state);
|
|
11
11
|
const managedFile = nextState.managedFiles[preview.relativePath] ?? preview.managedFile;
|
|
@@ -20,6 +20,7 @@ export function applySyncAction({ rootPath, state, manifest, preview, action, })
|
|
|
20
20
|
selectedFrameworkSkills: getSelectedFrameworkSkillsFromState(nextState),
|
|
21
21
|
selectedArchitectureSkill: getSelectedArchitectureSkillFromState(nextState),
|
|
22
22
|
selectedWorkflowSkills: getSelectedWorkflowSkillsFromState(nextState),
|
|
23
|
+
selectedDatabaseSkills: getSelectedDatabaseSkillsFromState(nextState),
|
|
23
24
|
});
|
|
24
25
|
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
25
26
|
fs.writeFileSync(targetPath, contents, 'utf8');
|
|
@@ -56,6 +57,7 @@ export function applySyncAction({ rootPath, state, manifest, preview, action, })
|
|
|
56
57
|
selectedFrameworkSkills: getSelectedFrameworkSkillsFromState(state),
|
|
57
58
|
selectedArchitectureSkill: getSelectedArchitectureSkillFromState(state),
|
|
58
59
|
selectedWorkflowSkills: getSelectedWorkflowSkillsFromState(state),
|
|
60
|
+
selectedDatabaseSkills: getSelectedDatabaseSkillsFromState(state),
|
|
59
61
|
});
|
|
60
62
|
fs.mkdirSync(path.dirname(sideTemplatePath), { recursive: true });
|
|
61
63
|
fs.writeFileSync(sideTemplatePath, contents, 'utf8');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -2,13 +2,13 @@ import { intro, log, outro } from '@clack/prompts';
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { STATE_RELATIVE_PATH } from '../../shared/catalog.js';
|
|
4
4
|
import { getProjectContext } from '../../shared/paths.js';
|
|
5
|
-
import { askForMissingFrameworkSkills, askForNewArchitectureSkill, askForNewLanguageSkills, renderIntro } from '
|
|
6
|
-
import { readStateForDoctor, writeStateFile } from '
|
|
7
|
-
import { readTemplateManifest } from '
|
|
5
|
+
import { askForMissingFrameworkSkills, askForNewArchitectureSkill, askForNewLanguageSkills, renderIntro } from '../interactive-guidance/index.js';
|
|
6
|
+
import { readStateForDoctor, writeStateFile } from '../workflow-state-registry/index.js';
|
|
7
|
+
import { readTemplateManifest } from '../template-catalog-rendering/index.js';
|
|
8
8
|
import { askForSyncAction } from './action-prompt.js';
|
|
9
9
|
import { applySyncAction } from './apply-action.js';
|
|
10
10
|
import { logSyncPreview } from './log-preview.js';
|
|
11
|
-
import { getSyncPreviews, isActionableSyncPreview, shouldAskForSyncAction } from './preview.js';
|
|
11
|
+
import { getSyncPreviews, isActionableSyncPreview, shouldAskForSyncAction } from './sync-preview.js';
|
|
12
12
|
export async function handleSyncProject(_command) {
|
|
13
13
|
await renderIntro();
|
|
14
14
|
intro(chalk.cyan('Reviewing workflow updates'));
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { askForSyncAction } from './action-prompt.js';
|
|
2
|
+
export { applySyncAction } from './apply-action.js';
|
|
3
|
+
export { handleSyncProject } from './handler.js';
|
|
4
|
+
export { logSyncPreview } from './log-preview.js';
|
|
5
|
+
export { getSyncPreviews, isActionableSyncPreview, shouldAskForSyncAction } from './sync-preview.js';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { sha256 } from '
|
|
4
|
-
import { hasReviewedTemplateVersion } from '
|
|
5
|
-
import { renderTemplateForSync } from '
|
|
6
|
-
import { getSelectedAgentsFromState, getSelectedArchitectureSkillFromState, getSelectedFrameworkSkillsFromState, getSelectedLanguageSkillsFromState, getSelectedWorkflowSkillsFromState, getWorkflowTargets, } from '
|
|
3
|
+
import { sha256 } from '../../shared/hash.js';
|
|
4
|
+
import { hasReviewedTemplateVersion } from '../workflow-state-registry/index.js';
|
|
5
|
+
import { renderTemplateForSync } from '../template-catalog-rendering/index.js';
|
|
6
|
+
import { getSelectedAgentsFromState, getSelectedArchitectureSkillFromState, getSelectedDatabaseSkillsFromState, getSelectedFrameworkSkillsFromState, getSelectedLanguageSkillsFromState, getSelectedWorkflowSkillsFromState, getWorkflowTargets, } from '../workflow-target-planning/index.js';
|
|
7
7
|
const ACTIONABLE_SYNC_PREVIEW_STATUSES = new Set([
|
|
8
8
|
'new-template',
|
|
9
9
|
'missing',
|
|
@@ -30,6 +30,7 @@ export function getSyncPreviews({ rootPath, state, manifest }) {
|
|
|
30
30
|
const selectedFrameworkSkills = getSelectedFrameworkSkillsFromState(state);
|
|
31
31
|
const selectedArchitectureSkill = getSelectedArchitectureSkillFromState(state);
|
|
32
32
|
const selectedWorkflowSkills = getSelectedWorkflowSkillsFromState(state);
|
|
33
|
+
const selectedDatabaseSkills = getSelectedDatabaseSkillsFromState(state);
|
|
33
34
|
const previews = Object.entries(state.managedFiles).map(([relativePath, managedFile]) => getManagedFileSyncPreview({
|
|
34
35
|
rootPath,
|
|
35
36
|
manifest,
|
|
@@ -39,8 +40,9 @@ export function getSyncPreviews({ rootPath, state, manifest }) {
|
|
|
39
40
|
selectedFrameworkSkills,
|
|
40
41
|
selectedArchitectureSkill,
|
|
41
42
|
selectedWorkflowSkills,
|
|
43
|
+
selectedDatabaseSkills,
|
|
42
44
|
}));
|
|
43
|
-
const expectedTargets = getWorkflowTargets(rootPath, getSelectedAgentsFromState(state), selectedLanguageSkills, selectedFrameworkSkills, selectedArchitectureSkill, selectedWorkflowSkills);
|
|
45
|
+
const expectedTargets = getWorkflowTargets(rootPath, getSelectedAgentsFromState(state), selectedLanguageSkills, selectedFrameworkSkills, selectedArchitectureSkill, selectedWorkflowSkills, selectedDatabaseSkills);
|
|
44
46
|
for (const target of expectedTargets) {
|
|
45
47
|
const relativePath = path.relative(rootPath, target.targetPath);
|
|
46
48
|
if (state.managedFiles[relativePath]) {
|
|
@@ -77,7 +79,7 @@ export function getSyncPreviews({ rootPath, state, manifest }) {
|
|
|
77
79
|
}
|
|
78
80
|
return previews;
|
|
79
81
|
}
|
|
80
|
-
function getManagedFileSyncPreview({ rootPath, manifest, relativePath, managedFile, selectedLanguageSkills, selectedFrameworkSkills, selectedArchitectureSkill, selectedWorkflowSkills, }) {
|
|
82
|
+
function getManagedFileSyncPreview({ rootPath, manifest, relativePath, managedFile, selectedLanguageSkills, selectedFrameworkSkills, selectedArchitectureSkill, selectedWorkflowSkills, selectedDatabaseSkills, }) {
|
|
81
83
|
if (managedFile.status === 'unmanaged') {
|
|
82
84
|
return { relativePath, managedFile, status: 'unmanaged', recordedTemplateVersion: managedFile.templateVersion, changes: [] };
|
|
83
85
|
}
|
|
@@ -97,6 +99,7 @@ function getManagedFileSyncPreview({ rootPath, manifest, relativePath, managedFi
|
|
|
97
99
|
selectedFrameworkSkills,
|
|
98
100
|
selectedArchitectureSkill,
|
|
99
101
|
selectedWorkflowSkills,
|
|
102
|
+
selectedDatabaseSkills,
|
|
100
103
|
});
|
|
101
104
|
const hasUpdate = hasTemplateUpdate || hasSelectionUpdate;
|
|
102
105
|
const changes = hasTemplateUpdate ? template.changes : ['Refreshes generated skill routing for the current selected skills.'];
|
|
@@ -154,7 +157,7 @@ function getManagedFileSyncPreview({ rootPath, manifest, relativePath, managedFi
|
|
|
154
157
|
hasLocalFile,
|
|
155
158
|
};
|
|
156
159
|
}
|
|
157
|
-
function hasRenderedSelectionUpdate({ relativePath, currentPath, managedFile, selectedLanguageSkills, selectedFrameworkSkills, selectedArchitectureSkill, selectedWorkflowSkills, }) {
|
|
160
|
+
function hasRenderedSelectionUpdate({ relativePath, currentPath, managedFile, selectedLanguageSkills, selectedFrameworkSkills, selectedArchitectureSkill, selectedWorkflowSkills, selectedDatabaseSkills, }) {
|
|
158
161
|
if (relativePath !== 'AGENTS.md') {
|
|
159
162
|
return false;
|
|
160
163
|
}
|
|
@@ -165,6 +168,7 @@ function hasRenderedSelectionUpdate({ relativePath, currentPath, managedFile, se
|
|
|
165
168
|
selectedFrameworkSkills,
|
|
166
169
|
selectedArchitectureSkill,
|
|
167
170
|
selectedWorkflowSkills,
|
|
171
|
+
selectedDatabaseSkills,
|
|
168
172
|
});
|
|
169
173
|
return sha256(renderedContents) !== managedFile.sha256;
|
|
170
174
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { extractProjectOverview, getTemplateVersion, readTemplate, readTemplateManifest, renderSkillRouting, renderTemplateForSync, } from './templates.js';
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { getTemplatesPath } from '../../shared/paths.js';
|
|
4
|
+
export function readTemplate(relativePath) {
|
|
5
|
+
return fs.readFileSync(path.join(getTemplatesPath(), relativePath), 'utf8');
|
|
6
|
+
}
|
|
7
|
+
export function readTemplateManifest() {
|
|
8
|
+
const manifest = JSON.parse(fs.readFileSync(path.join(getTemplatesPath(), 'manifest.json'), 'utf8'));
|
|
9
|
+
if (!isTemplateManifest(manifest)) {
|
|
10
|
+
throw new Error('templates/manifest.json is not a valid template manifest.');
|
|
11
|
+
}
|
|
12
|
+
return manifest;
|
|
13
|
+
}
|
|
14
|
+
export function getTemplateVersion(manifest, templateRelativePath) {
|
|
15
|
+
const template = manifest.templates[templateRelativePath];
|
|
16
|
+
if (!template) {
|
|
17
|
+
throw new Error(`Template ${templateRelativePath} is missing from templates/manifest.json.`);
|
|
18
|
+
}
|
|
19
|
+
return template.version;
|
|
20
|
+
}
|
|
21
|
+
export function renderTemplateForSync({ templateRelativePath, currentPath, selectedLanguageSkills, selectedFrameworkSkills, selectedArchitectureSkill, selectedWorkflowSkills = [], selectedDatabaseSkills = [], }) {
|
|
22
|
+
let contents = readTemplate(templateRelativePath);
|
|
23
|
+
if (contents.includes('{{PROJECT_OVERVIEW}}')) {
|
|
24
|
+
contents = contents.replace('{{PROJECT_OVERVIEW}}', extractProjectOverview(currentPath) ?? 'Describe this project.');
|
|
25
|
+
}
|
|
26
|
+
return renderSkillRouting(contents, selectedLanguageSkills, selectedFrameworkSkills, selectedArchitectureSkill, selectedWorkflowSkills, selectedDatabaseSkills);
|
|
27
|
+
}
|
|
28
|
+
export function renderSkillRouting(contents, selectedLanguageSkills, selectedFrameworkSkills, selectedArchitectureSkill, selectedWorkflowSkills = [], selectedDatabaseSkills = []) {
|
|
29
|
+
if (!contents.includes('{{OPTIONAL_SKILL_ROUTING}}')) {
|
|
30
|
+
return contents;
|
|
31
|
+
}
|
|
32
|
+
const optionalRouting = [...selectedLanguageSkills, ...selectedFrameworkSkills, ...selectedDatabaseSkills, ...(selectedArchitectureSkill ? [selectedArchitectureSkill] : []), ...selectedWorkflowSkills]
|
|
33
|
+
.map((skill) => `- ${skill.routingInstruction}`)
|
|
34
|
+
.join('\n');
|
|
35
|
+
return contents.replace('{{OPTIONAL_SKILL_ROUTING}}', optionalRouting);
|
|
36
|
+
}
|
|
37
|
+
export function extractProjectOverview(filePath) {
|
|
38
|
+
if (!fs.existsSync(filePath)) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
const contents = fs.readFileSync(filePath, 'utf8');
|
|
42
|
+
const match = contents.match(/## Project overview\s+([\s\S]*?)(?=\n## |$)/);
|
|
43
|
+
const overview = match?.[1]?.trim();
|
|
44
|
+
return overview || undefined;
|
|
45
|
+
}
|
|
46
|
+
function isTemplateManifest(value) {
|
|
47
|
+
if (!value || typeof value !== 'object') {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const manifest = value;
|
|
51
|
+
return (typeof manifest.templateVersion === 'string' &&
|
|
52
|
+
!!manifest.templates &&
|
|
53
|
+
typeof manifest.templates === 'object' &&
|
|
54
|
+
Object.values(manifest.templates).every((template) => !!template &&
|
|
55
|
+
typeof template === 'object' &&
|
|
56
|
+
typeof template.version === 'string' &&
|
|
57
|
+
typeof template.description === 'string' &&
|
|
58
|
+
Array.isArray(template.changes) &&
|
|
59
|
+
template.changes.every((change) => typeof change === 'string')));
|
|
60
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { checkForLatestSibuVersion, SIBU_CACHE_HOME_ENV, SIBU_PACKAGE_NAME, SIBU_VERSION } from './npm-version.js';
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
2
3
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
4
|
-
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
export const SIBU_PACKAGE_NAME = '@juancr11/sibu';
|
|
6
|
+
export const SIBU_VERSION = readPackageVersion();
|
|
7
|
+
export const NPM_VERSION_LOOKUP_MODE_ENV = 'SIBU_NPM_LOOKUP_MODE';
|
|
8
|
+
export const NPM_VERSION_OVERRIDE_ENV = 'SIBU_NPM_LATEST_VERSION';
|
|
9
|
+
export const SIBU_CACHE_HOME_ENV = 'SIBU_CACHE_HOME';
|
|
10
|
+
export const SUPPORTED_NPM_LOOKUP_MODES = ['live', 'offline'];
|
|
5
11
|
const NPM_VERSION_CACHE_TTL_MS = 6 * 60 * 60 * 1000;
|
|
6
12
|
const NPM_REGISTRY_URL = 'https://registry.npmjs.org';
|
|
7
13
|
export async function checkForLatestSibuVersion(options = {}) {
|
|
@@ -176,3 +182,24 @@ function isNpmVersionCacheRecord(value) {
|
|
|
176
182
|
typeof record.packageName === 'string' &&
|
|
177
183
|
typeof record.source === 'string');
|
|
178
184
|
}
|
|
185
|
+
function getNpmVersionCachePath() {
|
|
186
|
+
return path.join(getSibuCacheRoot(), 'cache', 'npm-version.json');
|
|
187
|
+
}
|
|
188
|
+
function getSibuCacheRoot() {
|
|
189
|
+
const override = process.env[SIBU_CACHE_HOME_ENV]?.trim();
|
|
190
|
+
if (override) {
|
|
191
|
+
return path.resolve(override);
|
|
192
|
+
}
|
|
193
|
+
return path.join(os.homedir(), '.sibu');
|
|
194
|
+
}
|
|
195
|
+
function readPackageVersion() {
|
|
196
|
+
const packageJsonPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..', 'package.json');
|
|
197
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
198
|
+
if (!isPackageJsonWithVersion(packageJson)) {
|
|
199
|
+
throw new Error(`Could not read Sibu version from ${packageJsonPath}.`);
|
|
200
|
+
}
|
|
201
|
+
return packageJson.version;
|
|
202
|
+
}
|
|
203
|
+
function isPackageJsonWithVersion(value) {
|
|
204
|
+
return Boolean(value && typeof value === 'object' && typeof value.version === 'string');
|
|
205
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -2,14 +2,15 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { intro, log, outro } from '@clack/prompts';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
-
import {
|
|
5
|
+
import { STATE_RELATIVE_PATH } from '../../shared/catalog.js';
|
|
6
|
+
import { SELECTABLE_ARCHITECTURE_SKILLS, SELECTABLE_DATABASE_SKILLS, SELECTABLE_FRAMEWORK_SKILLS, SELECTABLE_LANGUAGE_SKILLS, SUPPORTED_AGENTS } from '../workflow-target-planning/index.js';
|
|
6
7
|
import { sha256 } from '../../shared/hash.js';
|
|
7
|
-
import { checkForLatestSibuVersion } from '
|
|
8
|
+
import { checkForLatestSibuVersion } from '../version-advisory/index.js';
|
|
8
9
|
import { getProjectContext } from '../../shared/paths.js';
|
|
9
|
-
import { renderIntro } from '
|
|
10
|
-
import { hasReviewedTemplateVersion, readStateForDoctor } from '
|
|
11
|
-
import { getTemplateVersion, readTemplateManifest } from '
|
|
12
|
-
import { getSelectedAgentsFromState, getSelectedArchitectureSkillFromState, getSelectedFrameworkSkillsFromState, getSelectedLanguageSkillsFromState, getWorkflowTargets, } from '
|
|
10
|
+
import { renderIntro } from '../interactive-guidance/index.js';
|
|
11
|
+
import { hasReviewedTemplateVersion, readStateForDoctor } from '../workflow-state-registry/index.js';
|
|
12
|
+
import { getTemplateVersion, readTemplateManifest } from '../template-catalog-rendering/index.js';
|
|
13
|
+
import { getSelectedAgentsFromState, getSelectedArchitectureSkillFromState, getSelectedDatabaseSkillsFromState, getSelectedFrameworkSkillsFromState, getSelectedLanguageSkillsFromState, getSelectedWorkflowSkillsFromState, getWorkflowTargets, } from '../workflow-target-planning/index.js';
|
|
13
14
|
export async function handleDoctorProject(_command) {
|
|
14
15
|
await renderIntro();
|
|
15
16
|
intro(chalk.cyan('Checking workflow state'));
|
|
@@ -116,6 +117,11 @@ function addUnsupportedSelectionIssues(state, issues) {
|
|
|
116
117
|
if (state.selectedArchitectureSkill && !SELECTABLE_ARCHITECTURE_SKILLS.some((skill) => skill.id === state.selectedArchitectureSkill)) {
|
|
117
118
|
issues.push({ severity: 'warning', message: `State references unsupported architecture skill: ${state.selectedArchitectureSkill}.` });
|
|
118
119
|
}
|
|
120
|
+
for (const selectedDatabaseSkill of state.selectedDatabaseSkills ?? []) {
|
|
121
|
+
if (!SELECTABLE_DATABASE_SKILLS.some((skill) => skill.id === selectedDatabaseSkill)) {
|
|
122
|
+
issues.push({ severity: 'warning', message: `State references unsupported database skill: ${selectedDatabaseSkill}.` });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
119
125
|
for (const reviewedArchitectureSkill of state.reviewedArchitectureSkills ?? []) {
|
|
120
126
|
if (!SELECTABLE_ARCHITECTURE_SKILLS.some((skill) => skill.id === reviewedArchitectureSkill)) {
|
|
121
127
|
issues.push({ severity: 'warning', message: `State references unsupported reviewed architecture skill: ${reviewedArchitectureSkill}.` });
|
|
@@ -124,7 +130,7 @@ function addUnsupportedSelectionIssues(state, issues) {
|
|
|
124
130
|
}
|
|
125
131
|
function addExpectedTargetIssues(rootPath, state, issues) {
|
|
126
132
|
const reportedMissingPaths = new Set();
|
|
127
|
-
const expectedTargets = getWorkflowTargets(rootPath, getSelectedAgentsFromState(state), getSelectedLanguageSkillsFromState(state), getSelectedFrameworkSkillsFromState(state), getSelectedArchitectureSkillFromState(state));
|
|
133
|
+
const expectedTargets = getWorkflowTargets(rootPath, getSelectedAgentsFromState(state), getSelectedLanguageSkillsFromState(state), getSelectedFrameworkSkillsFromState(state), getSelectedArchitectureSkillFromState(state), getSelectedWorkflowSkillsFromState(state), getSelectedDatabaseSkillsFromState(state));
|
|
128
134
|
for (const target of expectedTargets) {
|
|
129
135
|
const relativePath = path.relative(rootPath, target.targetPath);
|
|
130
136
|
const managedFile = state.managedFiles[relativePath];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { diagnoseState, getDoctorSyncNextStepLines, getNpmVersionAdvisoryLines, handleDoctorProject } from './handler.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getWorkflowMutationReadiness } from './workflow-mutation-readiness.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { readStateForDoctor } from '
|
|
2
|
-
import { getSyncPreviews, isActionableSyncPreview } from '
|
|
3
|
-
import { readTemplateManifest } from '
|
|
1
|
+
import { readStateForDoctor } from '../workflow-state-registry/index.js';
|
|
2
|
+
import { getSyncPreviews, isActionableSyncPreview } from '../sync-review/index.js';
|
|
3
|
+
import { readTemplateManifest } from '../template-catalog-rendering/index.js';
|
|
4
4
|
export function getWorkflowMutationReadiness({ rootPath, statePath }) {
|
|
5
5
|
const stateResult = readStateForDoctor(statePath);
|
|
6
6
|
if (!stateResult.ok) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { cloneState, hasReviewedTemplateVersion, readExistingState, readStateForDoctor, writeStateFile } from './state.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { STATE_RELATIVE_PATH } from '
|
|
3
|
+
import { STATE_RELATIVE_PATH } from '../../shared/catalog.js';
|
|
4
4
|
export function readStateForDoctor(statePath) {
|
|
5
5
|
if (!fs.existsSync(statePath)) {
|
|
6
6
|
return { ok: false, message: `${STATE_RELATIVE_PATH} is missing.` };
|
|
@@ -57,6 +57,8 @@ function isSibuState(value) {
|
|
|
57
57
|
(state.selectedArchitectureSkill === undefined || typeof state.selectedArchitectureSkill === 'string') &&
|
|
58
58
|
(state.selectedWorkflowSkills === undefined ||
|
|
59
59
|
(Array.isArray(state.selectedWorkflowSkills) && state.selectedWorkflowSkills.every((skill) => typeof skill === 'string'))) &&
|
|
60
|
+
(state.selectedDatabaseSkills === undefined ||
|
|
61
|
+
(Array.isArray(state.selectedDatabaseSkills) && state.selectedDatabaseSkills.every((skill) => typeof skill === 'string'))) &&
|
|
60
62
|
(state.reviewedArchitectureSkills === undefined ||
|
|
61
63
|
(Array.isArray(state.reviewedArchitectureSkills) && state.reviewedArchitectureSkills.every((skill) => typeof skill === 'string'))) &&
|
|
62
64
|
!!state.managedFiles &&
|