@juancr11/sibu 0.9.7 → 0.11.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/README.md +25 -4
- package/bin/modules/interactive-guidance/index.js +1 -1
- package/bin/modules/interactive-guidance/prompts.js +16 -0
- package/bin/modules/mcp-server-selection-management/stop-mcp-server/handler.js +4 -0
- package/bin/modules/mcp-server-selection-management/use-mcp-server/handler.js +21 -4
- package/bin/modules/project-adoption/handler.js +4 -1
- package/bin/modules/template-catalog-rendering/templates.js +37 -10
- package/bin/modules/workflow-state-registry/state.js +17 -0
- package/bin/modules/workflow-target-planning/catalog.js +6 -0
- package/bin/modules/workflow-target-planning/workflow-targets.js +3 -2
- package/package.json +1 -1
- package/templates/manifest.json +13 -13
- package/templates/skills/architecture/command-pattern/SKILL.md +31 -0
- package/templates/skills/architecture/ddd-hexagonal/SKILL.md +28 -0
- package/templates/skills/feature-brief-writer/SKILL.md +25 -0
- package/templates/skills/nextjs/SKILL.md +5 -3
- package/templates/skills/technical-design-writer/SKILL.md +29 -0
- package/templates/skills/ux-expert/SKILL.md +25 -0
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ Use `sibu skills stop <file>` to stop managing an Sibu-tracked workflow file. Th
|
|
|
44
44
|
|
|
45
45
|
## MCP server setup
|
|
46
46
|
|
|
47
|
-
Sibu can generate MCP server configuration for supported agents.
|
|
47
|
+
Sibu can generate MCP server configuration for supported agents. Supported MCP servers include GitHub and Notion.
|
|
48
48
|
|
|
49
49
|
Sibu only writes and tracks MCP config files. Runtime prerequisites, credentials, and provider authentication remain user-owned.
|
|
50
50
|
|
|
@@ -121,15 +121,36 @@ export GITHUB_PERSONAL_ACCESS_TOKEN=your_token_here
|
|
|
121
121
|
|
|
122
122
|
Do not commit tokens or write them into Sibu-managed config files. The generated configs read `GITHUB_PERSONAL_ACCESS_TOKEN` from the environment so credentials can stay outside the repository.
|
|
123
123
|
|
|
124
|
-
### 4.
|
|
124
|
+
### 4. Configure the Notion MCP server
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
You can select Notion during `sibu init`, or add it later:
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
sibu mcp use notion
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
When Notion is selected, Sibu asks for a Notion docs destination parent page URL or page ID. Sibu stores that parent page reference in `.sibu/state.json` so feature-doc export guidance knows where Notion pages should go.
|
|
133
|
+
|
|
134
|
+
Sibu configures supported agent MCP files for Notion, but it does not manage Notion OAuth login, workspace selection, integration installation, page permissions, credentials, or live connectivity. Your Notion MCP connection must be authenticated separately and must have access to the configured parent page. For provider setup details, use Notion's MCP documentation: <https://developers.notion.com/guides/mcp/get-started-with-mcp>.
|
|
135
|
+
|
|
136
|
+
Feature briefs, technical designs, and UX docs are still written to local Markdown first. Notion is an optional export destination, not Sibu's source of truth.
|
|
137
|
+
|
|
138
|
+
For Codex with the hosted Notion MCP server, you may need to run the agent-specific MCP login flow after Sibu writes config, such as:
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
codex mcp login notion
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 5. Stop managing an MCP server
|
|
145
|
+
|
|
146
|
+
To remove a selected MCP server from Sibu's state, run:
|
|
127
147
|
|
|
128
148
|
```sh
|
|
129
149
|
sibu mcp stop github
|
|
150
|
+
sibu mcp stop notion
|
|
130
151
|
```
|
|
131
152
|
|
|
132
|
-
Sibu updates generated agent config where possible and asks whether to keep or delete MCP-only config files.
|
|
153
|
+
Sibu updates generated agent config where possible and asks whether to keep or delete MCP-only config files. Stopping Notion only updates local Sibu state and managed MCP config files; it does not delete Notion pages or change Notion permissions.
|
|
133
154
|
|
|
134
155
|
## Release notes and changelog
|
|
135
156
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { askForArchitectureSkill, askForDatabaseSkills, askForFrameworkSkills, askForLanguageSkills, askForMcpServers, askForMissingFrameworkSkills, askForNewArchitectureSkill, askForNewLanguageSkills, askForProjectOverview, askForSupportedAgents, askForWorkflowSkills, MCP_SERVER_SELECTION_MESSAGE, renderIntro, shouldAskForNewLanguageSkills, } from './prompts.js';
|
|
1
|
+
export { askForArchitectureSkill, askForDatabaseSkills, askForFrameworkSkills, askForLanguageSkills, askForMcpServers, askForNotionDocsParentPage, askForMissingFrameworkSkills, askForNewArchitectureSkill, askForNewLanguageSkills, askForProjectOverview, askForSupportedAgents, askForWorkflowSkills, MCP_SERVER_SELECTION_MESSAGE, renderIntro, shouldAskForNewLanguageSkills, } from './prompts.js';
|
|
@@ -89,6 +89,22 @@ export async function askForMcpServers() {
|
|
|
89
89
|
}
|
|
90
90
|
return SELECTABLE_MCP_SERVERS.filter((server) => selectedMcpServerIds.includes(server.id));
|
|
91
91
|
}
|
|
92
|
+
export async function askForNotionDocsParentPage() {
|
|
93
|
+
const parentPage = await text({
|
|
94
|
+
message: 'Enter the Notion docs destination parent page URL or page ID.',
|
|
95
|
+
placeholder: 'https://www.notion.so/workspace/Sibu-Docs-...',
|
|
96
|
+
validate(value) {
|
|
97
|
+
if (!value?.trim()) {
|
|
98
|
+
return 'Enter a Notion parent page that your Notion MCP connection can access.';
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
if (isCancel(parentPage)) {
|
|
103
|
+
cancel('Initialization cancelled.');
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
|
106
|
+
return parentPage.trim();
|
|
107
|
+
}
|
|
92
108
|
async function askForFrameworkSkillSelection({ message, cancelMessage, }) {
|
|
93
109
|
const selectedFrameworkSkillIds = await multiselect({
|
|
94
110
|
message,
|
|
@@ -79,6 +79,10 @@ export function stopSelectedMcpServer({ rootPath, state, serverId }) {
|
|
|
79
79
|
const stoppedPaths = [];
|
|
80
80
|
const stoppedFiles = [];
|
|
81
81
|
nextState.selectedMcpServers = selectionResult.remainingMcpServers.map((server) => server.id);
|
|
82
|
+
if (serverId === 'notion' && nextState.mcpServerConfigs?.notion) {
|
|
83
|
+
const { notion: _notion, ...remainingMcpServerConfigs } = nextState.mcpServerConfigs;
|
|
84
|
+
nextState.mcpServerConfigs = Object.keys(remainingMcpServerConfigs).length > 0 ? remainingMcpServerConfigs : undefined;
|
|
85
|
+
}
|
|
82
86
|
nextState.templateVersion = manifest.templateVersion;
|
|
83
87
|
nextState.updatedAt = new Date().toISOString();
|
|
84
88
|
for (const previousTarget of previousTargets.filter((target) => target.mcpConfigAgentId)) {
|
|
@@ -3,9 +3,13 @@ import path from 'node:path';
|
|
|
3
3
|
import { log } from '@clack/prompts';
|
|
4
4
|
import { STATE_RELATIVE_PATH } from '../../../shared/catalog.js';
|
|
5
5
|
import { getProjectContext } from '../../../shared/paths.js';
|
|
6
|
+
import { askForNotionDocsParentPage } from '../../interactive-guidance/index.js';
|
|
6
7
|
import { getWorkflowMutationReadiness } from '../../workflow-mutation-readiness/index.js';
|
|
7
8
|
import { getSelectedAgentsFromState, getSelectedArchitectureSkillFromState, getSelectedDatabaseSkillsFromState, getSelectedFrameworkSkillsFromState, getSelectedLanguageSkillsFromState, getSelectedMcpServersFromState, getSelectedWorkflowSkillsFromState, getWorkflowTargets, renderMissingWorkflowFiles, resolveSelectableMcpServerById, writeSibuState, } from '../../workflow-target-planning/index.js';
|
|
8
|
-
|
|
9
|
+
const defaultDependencies = {
|
|
10
|
+
askForNotionDocsParentPage,
|
|
11
|
+
};
|
|
12
|
+
export async function handleUseMcpServer(command, dependencies = defaultDependencies) {
|
|
9
13
|
const { rootPath, statePath } = getProjectContext();
|
|
10
14
|
const readiness = getWorkflowMutationReadiness({ rootPath, statePath });
|
|
11
15
|
if (!readiness.ok) {
|
|
@@ -30,9 +34,11 @@ export async function handleUseMcpServer(command) {
|
|
|
30
34
|
}
|
|
31
35
|
process.exitCode = 1;
|
|
32
36
|
return;
|
|
33
|
-
case 'selected':
|
|
34
|
-
|
|
37
|
+
case 'selected': {
|
|
38
|
+
const mcpServerConfigs = await getNextMcpServerConfigs({ state: readiness.state, selectionResult, dependencies });
|
|
39
|
+
applySelectedMcpServer({ rootPath, statePath, state: readiness.state, selectionResult, mcpServerConfigs });
|
|
35
40
|
return;
|
|
41
|
+
}
|
|
36
42
|
}
|
|
37
43
|
}
|
|
38
44
|
export function getNextMcpSelection(state, serverId) {
|
|
@@ -50,7 +56,17 @@ export function getNextMcpSelection(state, serverId) {
|
|
|
50
56
|
selectedMcpServers: [...selectedMcpServerIds, resolution.resolved.server.id].map(getMcpServerById),
|
|
51
57
|
};
|
|
52
58
|
}
|
|
53
|
-
function
|
|
59
|
+
async function getNextMcpServerConfigs({ state, selectionResult, dependencies, }) {
|
|
60
|
+
if (!selectionResult.selectedMcpServers.some((server) => server.id === 'notion') || state.selectedMcpServers?.includes('notion')) {
|
|
61
|
+
return state.mcpServerConfigs;
|
|
62
|
+
}
|
|
63
|
+
const docsParentPage = await dependencies.askForNotionDocsParentPage();
|
|
64
|
+
return {
|
|
65
|
+
...state.mcpServerConfigs,
|
|
66
|
+
notion: { docsParentPage },
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function applySelectedMcpServer({ rootPath, statePath, state, selectionResult, mcpServerConfigs, }) {
|
|
54
70
|
const selectedAgents = getSelectedAgentsFromState(state);
|
|
55
71
|
const selectedLanguageSkills = getSelectedLanguageSkillsFromState(state);
|
|
56
72
|
const selectedFrameworkSkills = getSelectedFrameworkSkillsFromState(state);
|
|
@@ -92,6 +108,7 @@ function applySelectedMcpServer({ rootPath, statePath, state, selectionResult, }
|
|
|
92
108
|
selectedWorkflowSkills,
|
|
93
109
|
selectedDatabaseSkills,
|
|
94
110
|
selectedMcpServers: selectionResult.selectedMcpServers,
|
|
111
|
+
mcpServerConfigs,
|
|
95
112
|
targets,
|
|
96
113
|
});
|
|
97
114
|
log.success(`Updated ${STATE_RELATIVE_PATH}`);
|
|
@@ -4,13 +4,14 @@ import { intro, log, outro } from '@clack/prompts';
|
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import { STATE_RELATIVE_PATH } from '../../shared/catalog.js';
|
|
6
6
|
import { getProjectContext } from '../../shared/paths.js';
|
|
7
|
-
import { askForArchitectureSkill, askForDatabaseSkills, askForFrameworkSkills, askForLanguageSkills, askForMcpServers, askForProjectOverview, askForSupportedAgents, askForWorkflowSkills, renderIntro, } from '../interactive-guidance/index.js';
|
|
7
|
+
import { askForArchitectureSkill, askForDatabaseSkills, askForFrameworkSkills, askForLanguageSkills, askForMcpServers, askForNotionDocsParentPage, askForProjectOverview, askForSupportedAgents, askForWorkflowSkills, renderIntro, } from '../interactive-guidance/index.js';
|
|
8
8
|
import { readStateForDoctor } from '../workflow-state-registry/index.js';
|
|
9
9
|
import { getWorkflowTargets, renderMissingWorkflowFiles, writeSibuState } from '../workflow-target-planning/index.js';
|
|
10
10
|
const defaultDependencies = {
|
|
11
11
|
renderIntro,
|
|
12
12
|
askForSupportedAgents,
|
|
13
13
|
askForMcpServers,
|
|
14
|
+
askForNotionDocsParentPage,
|
|
14
15
|
askForLanguageSkills,
|
|
15
16
|
askForFrameworkSkills,
|
|
16
17
|
askForDatabaseSkills,
|
|
@@ -40,6 +41,7 @@ export async function handleInitProject(_command, dependencies = defaultDependen
|
|
|
40
41
|
}
|
|
41
42
|
const selectedAgents = await dependencies.askForSupportedAgents();
|
|
42
43
|
const selectedMcpServers = await dependencies.askForMcpServers();
|
|
44
|
+
const notionDocsParentPage = selectedMcpServers.some((server) => server.id === 'notion') ? await dependencies.askForNotionDocsParentPage() : undefined;
|
|
43
45
|
const selectedLanguageSkills = await dependencies.askForLanguageSkills();
|
|
44
46
|
const selectedFrameworkSkills = await dependencies.askForFrameworkSkills();
|
|
45
47
|
const selectedDatabaseSkills = await dependencies.askForDatabaseSkills();
|
|
@@ -84,6 +86,7 @@ export async function handleInitProject(_command, dependencies = defaultDependen
|
|
|
84
86
|
selectedWorkflowSkills,
|
|
85
87
|
selectedDatabaseSkills,
|
|
86
88
|
selectedMcpServers,
|
|
89
|
+
mcpServerConfigs: notionDocsParentPage ? { notion: { docsParentPage: notionDocsParentPage } } : undefined,
|
|
87
90
|
targets,
|
|
88
91
|
});
|
|
89
92
|
log.success(`Created ${STATE_RELATIVE_PATH}`);
|
|
@@ -39,16 +39,13 @@ export function renderSkillRouting(contents, selectedLanguageSkills, selectedFra
|
|
|
39
39
|
return contents.replace('{{OPTIONAL_SKILL_ROUTING}}', optionalRouting);
|
|
40
40
|
}
|
|
41
41
|
export function renderMcpConfig({ agentId, baseContents, selectedMcpServers, }) {
|
|
42
|
-
|
|
43
|
-
if (!githubServer) {
|
|
42
|
+
if (selectedMcpServers.length === 0) {
|
|
44
43
|
return baseContents ?? renderJsonMcpConfig({});
|
|
45
44
|
}
|
|
46
45
|
if (agentId === 'codex') {
|
|
47
|
-
return
|
|
46
|
+
return renderCodexMcpConfig(baseContents ?? '', selectedMcpServers);
|
|
48
47
|
}
|
|
49
|
-
return renderJsonMcpConfig(
|
|
50
|
-
github: buildGithubMcpServerConfig(agentId),
|
|
51
|
-
});
|
|
48
|
+
return renderJsonMcpConfig(buildJsonMcpServerConfigs(agentId, selectedMcpServers));
|
|
52
49
|
}
|
|
53
50
|
export function extractProjectOverview(filePath) {
|
|
54
51
|
if (!fs.existsSync(filePath)) {
|
|
@@ -59,13 +56,26 @@ export function extractProjectOverview(filePath) {
|
|
|
59
56
|
const overview = match?.[1]?.trim();
|
|
60
57
|
return overview || undefined;
|
|
61
58
|
}
|
|
62
|
-
function
|
|
59
|
+
function renderCodexMcpConfig(baseContents, selectedMcpServers) {
|
|
63
60
|
const trimmedBaseContents = baseContents.trimEnd();
|
|
61
|
+
const serverConfigs = selectedMcpServers.map((server) => buildCodexMcpServerConfig(server)).filter((config) => config.length > 0);
|
|
62
|
+
if (serverConfigs.length === 0) {
|
|
63
|
+
return baseContents;
|
|
64
|
+
}
|
|
64
65
|
const separator = trimmedBaseContents ? '\n\n' : '';
|
|
65
|
-
return `${trimmedBaseContents}${separator}
|
|
66
|
+
return `${trimmedBaseContents}${separator}${serverConfigs.join('\n\n')}\n`;
|
|
67
|
+
}
|
|
68
|
+
function buildCodexMcpServerConfig(server) {
|
|
69
|
+
if (server.id === 'github') {
|
|
70
|
+
return `[mcp_servers.github]
|
|
66
71
|
url = "https://api.githubcopilot.com/mcp/"
|
|
67
|
-
bearer_token_env_var = "GITHUB_PERSONAL_ACCESS_TOKEN"
|
|
68
|
-
|
|
72
|
+
bearer_token_env_var = "GITHUB_PERSONAL_ACCESS_TOKEN"`;
|
|
73
|
+
}
|
|
74
|
+
if (server.id === 'notion') {
|
|
75
|
+
return `[mcp_servers.notion]
|
|
76
|
+
url = "https://mcp.notion.com/mcp"`;
|
|
77
|
+
}
|
|
78
|
+
return '';
|
|
69
79
|
}
|
|
70
80
|
function getMcpConfigAgentId(templateRelativePath) {
|
|
71
81
|
if (templateRelativePath === '.codex/config.toml') {
|
|
@@ -79,6 +89,18 @@ function getMcpConfigAgentId(templateRelativePath) {
|
|
|
79
89
|
}
|
|
80
90
|
return undefined;
|
|
81
91
|
}
|
|
92
|
+
function buildJsonMcpServerConfigs(agentId, selectedMcpServers) {
|
|
93
|
+
const mcpServers = {};
|
|
94
|
+
for (const server of selectedMcpServers) {
|
|
95
|
+
if (server.id === 'github') {
|
|
96
|
+
mcpServers.github = buildGithubMcpServerConfig(agentId);
|
|
97
|
+
}
|
|
98
|
+
if (server.id === 'notion') {
|
|
99
|
+
mcpServers.notion = buildNotionMcpServerConfig();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return mcpServers;
|
|
103
|
+
}
|
|
82
104
|
function buildGithubMcpServerConfig(agentId) {
|
|
83
105
|
const headers = {
|
|
84
106
|
Authorization: 'Bearer ${GITHUB_PERSONAL_ACCESS_TOKEN}',
|
|
@@ -95,6 +117,11 @@ function buildGithubMcpServerConfig(agentId) {
|
|
|
95
117
|
headers,
|
|
96
118
|
};
|
|
97
119
|
}
|
|
120
|
+
function buildNotionMcpServerConfig() {
|
|
121
|
+
return {
|
|
122
|
+
url: 'https://mcp.notion.com/mcp',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
98
125
|
function renderJsonMcpConfig(mcpServers) {
|
|
99
126
|
return `${JSON.stringify({ mcpServers }, null, 2)}\n`;
|
|
100
127
|
}
|
|
@@ -61,12 +61,29 @@ function isSibuState(value) {
|
|
|
61
61
|
(Array.isArray(state.selectedDatabaseSkills) && state.selectedDatabaseSkills.every((skill) => typeof skill === 'string'))) &&
|
|
62
62
|
(state.selectedMcpServers === undefined ||
|
|
63
63
|
(Array.isArray(state.selectedMcpServers) && state.selectedMcpServers.every((server) => typeof server === 'string'))) &&
|
|
64
|
+
(state.mcpServerConfigs === undefined || isMcpServerConfigs(state.mcpServerConfigs)) &&
|
|
64
65
|
(state.reviewedArchitectureSkills === undefined ||
|
|
65
66
|
(Array.isArray(state.reviewedArchitectureSkills) && state.reviewedArchitectureSkills.every((skill) => typeof skill === 'string'))) &&
|
|
66
67
|
!!state.managedFiles &&
|
|
67
68
|
typeof state.managedFiles === 'object' &&
|
|
68
69
|
Object.values(state.managedFiles).every(isManagedFileState));
|
|
69
70
|
}
|
|
71
|
+
function isMcpServerConfigs(value) {
|
|
72
|
+
if (!value || typeof value !== 'object') {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
const configs = value;
|
|
76
|
+
if (configs.notion !== undefined) {
|
|
77
|
+
if (!configs.notion || typeof configs.notion !== 'object') {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const notionConfig = configs.notion;
|
|
81
|
+
if (typeof notionConfig.docsParentPage !== 'string') {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
70
87
|
function isManagedFileState(value) {
|
|
71
88
|
if (!value || typeof value !== 'object') {
|
|
72
89
|
return false;
|
|
@@ -206,6 +206,12 @@ export const SELECTABLE_MCP_SERVERS = [
|
|
|
206
206
|
description: "Configure GitHub's official MCP server; Sibu writes config only, while prerequisites, runtime availability, credentials, and authentication remain user-owned",
|
|
207
207
|
source: 'github/github-mcp-server',
|
|
208
208
|
},
|
|
209
|
+
{
|
|
210
|
+
id: 'notion',
|
|
211
|
+
name: 'Notion MCP Server',
|
|
212
|
+
description: 'Configure Notion MCP server access; Sibu writes config only, while OAuth authentication, workspace access, page permissions, and credentials remain user-owned',
|
|
213
|
+
source: 'developers.notion.com/guides/mcp',
|
|
214
|
+
},
|
|
209
215
|
];
|
|
210
216
|
export const SUPPORTED_AGENTS = [
|
|
211
217
|
{
|
|
@@ -49,7 +49,7 @@ export function getSelectedSkillTargetsForAgents(selectedAgents, selectedLanguag
|
|
|
49
49
|
return [...skillTargets.values()];
|
|
50
50
|
}
|
|
51
51
|
export function getSelectedMcpTargetsForAgents(selectedAgents, selectedMcpServers) {
|
|
52
|
-
if (
|
|
52
|
+
if (selectedMcpServers.length === 0) {
|
|
53
53
|
return [];
|
|
54
54
|
}
|
|
55
55
|
return selectedAgents.flatMap((agent) => {
|
|
@@ -158,7 +158,7 @@ export function renderMissingWorkflowFiles({ missingTargets, overview, selectedL
|
|
|
158
158
|
};
|
|
159
159
|
});
|
|
160
160
|
}
|
|
161
|
-
export function writeSibuState({ rootPath, statePath, selectedAgents, selectedLanguageSkills, selectedFrameworkSkills, selectedArchitectureSkill, selectedWorkflowSkills = [], selectedDatabaseSkills = [], selectedMcpServers, targets, }) {
|
|
161
|
+
export function writeSibuState({ rootPath, statePath, selectedAgents, selectedLanguageSkills, selectedFrameworkSkills, selectedArchitectureSkill, selectedWorkflowSkills = [], selectedDatabaseSkills = [], selectedMcpServers, mcpServerConfigs, targets, }) {
|
|
162
162
|
const previousState = readExistingState(statePath);
|
|
163
163
|
const now = new Date().toISOString();
|
|
164
164
|
const manifest = readTemplateManifest();
|
|
@@ -174,6 +174,7 @@ export function writeSibuState({ rootPath, statePath, selectedAgents, selectedLa
|
|
|
174
174
|
selectedWorkflowSkills: selectedWorkflowSkills.map((skill) => skill.id),
|
|
175
175
|
selectedDatabaseSkills: selectedDatabaseSkills.map((skill) => skill.id),
|
|
176
176
|
...(selectedMcpServers !== undefined ? { selectedMcpServers: selectedMcpServers.map((server) => server.id) } : {}),
|
|
177
|
+
...(mcpServerConfigs ?? previousState?.mcpServerConfigs ? { mcpServerConfigs: mcpServerConfigs ?? previousState?.mcpServerConfigs } : {}),
|
|
177
178
|
managedFiles: Object.fromEntries(targets
|
|
178
179
|
.filter((target) => fs.existsSync(target.targetPath))
|
|
179
180
|
.map((target) => {
|
package/package.json
CHANGED
package/templates/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"templateVersion": "
|
|
2
|
+
"templateVersion": "90",
|
|
3
3
|
"templates": {
|
|
4
4
|
"AGENTS.md": {
|
|
5
5
|
"version": "28",
|
|
@@ -66,17 +66,17 @@
|
|
|
66
66
|
]
|
|
67
67
|
},
|
|
68
68
|
"skills/feature-brief-writer/SKILL.md": {
|
|
69
|
-
"version": "
|
|
69
|
+
"version": "10",
|
|
70
70
|
"description": "Mandatory feature brief writer skill installed once at the shared .agents/skills workspace path.",
|
|
71
71
|
"changes": [
|
|
72
|
-
"
|
|
72
|
+
"Adds optional Notion export guidance after local feature briefs are written while keeping Markdown as the canonical artifact."
|
|
73
73
|
]
|
|
74
74
|
},
|
|
75
75
|
"skills/technical-design-writer/SKILL.md": {
|
|
76
|
-
"version": "
|
|
76
|
+
"version": "17",
|
|
77
77
|
"description": "Mandatory technical design writer skill installed once at the shared .agents/skills workspace path.",
|
|
78
78
|
"changes": [
|
|
79
|
-
"
|
|
79
|
+
"Adds optional Notion export guidance after local technical designs are written while keeping Markdown as the canonical artifact."
|
|
80
80
|
]
|
|
81
81
|
},
|
|
82
82
|
"skills/typescript/SKILL.md": {
|
|
@@ -101,24 +101,24 @@
|
|
|
101
101
|
]
|
|
102
102
|
},
|
|
103
103
|
"skills/architecture/ddd-hexagonal/SKILL.md": {
|
|
104
|
-
"version": "
|
|
104
|
+
"version": "8",
|
|
105
105
|
"description": "Selectable back-end architecture skill for DDD and Hexagonal Architecture.",
|
|
106
106
|
"changes": [
|
|
107
|
-
"Adds
|
|
107
|
+
"Adds a framework-agnostic adapter dependency rule requiring delivery entrypoints to call application/orchestration boundaries instead of infrastructure or domain workflow internals."
|
|
108
108
|
]
|
|
109
109
|
},
|
|
110
110
|
"skills/architecture/command-pattern/SKILL.md": {
|
|
111
|
-
"version": "
|
|
111
|
+
"version": "6",
|
|
112
112
|
"description": "Selectable architecture skill for command-oriented vertical slices using Command Pattern, Hexagonal Architecture, and DDD principles.",
|
|
113
113
|
"changes": [
|
|
114
|
-
"
|
|
114
|
+
"Adds a framework-agnostic entrypoint dependency rule requiring delivery adapters to create commands and call handlers or dispatchers instead of infrastructure, SDKs, repositories, or domain workflow internals."
|
|
115
115
|
]
|
|
116
116
|
},
|
|
117
117
|
"skills/nextjs/SKILL.md": {
|
|
118
|
-
"version": "
|
|
118
|
+
"version": "3",
|
|
119
119
|
"description": "Selectable framework skill for Next.js App Router and framework-specific behavior.",
|
|
120
120
|
"changes": [
|
|
121
|
-
"
|
|
121
|
+
"Keeps Next.js boundary guidance architecture-agnostic by referring to the selected orchestration/application boundary instead of naming a specific architecture."
|
|
122
122
|
]
|
|
123
123
|
},
|
|
124
124
|
"skills/react/SKILL.md": {
|
|
@@ -157,10 +157,10 @@
|
|
|
157
157
|
]
|
|
158
158
|
},
|
|
159
159
|
"skills/ux-expert/SKILL.md": {
|
|
160
|
-
"version": "
|
|
160
|
+
"version": "7",
|
|
161
161
|
"description": "Selectable UX expert skill for UI-changing features, responsive design, flows, states, accessibility, and binding mockups.",
|
|
162
162
|
"changes": [
|
|
163
|
-
"
|
|
163
|
+
"Adds optional Notion export guidance after local UX specs are written while keeping Markdown as the canonical artifact."
|
|
164
164
|
]
|
|
165
165
|
}
|
|
166
166
|
}
|
|
@@ -81,6 +81,37 @@ The Handler must be "blind" to the entrypoint. It should not know if it is being
|
|
|
81
81
|
### Rule 4: Thin Entrypoints
|
|
82
82
|
Entrypoints (CLI/API) are responsible for Syntactic Validation (is the input the right type?). Handlers are responsible for Semantic Validation (does this operation make sense in the current state of the system?).
|
|
83
83
|
|
|
84
|
+
### Rule 5: Entrypoints Call Commands, Not Lower Layers
|
|
85
|
+
Entrypoints are driving adapters. Examples include CLI commands, HTTP routes, Next.js App Router files, server actions, queue consumers, jobs, webhooks, RPC handlers, and GraphQL resolvers.
|
|
86
|
+
|
|
87
|
+
An entrypoint may:
|
|
88
|
+
- adapt framework or transport input into a Command
|
|
89
|
+
- call the feature Handler directly, or call an application-level command dispatcher/orchestration API
|
|
90
|
+
- translate the Result into a framework or transport response
|
|
91
|
+
|
|
92
|
+
An entrypoint must not directly import or call:
|
|
93
|
+
- infrastructure adapters
|
|
94
|
+
- database clients or repository implementations
|
|
95
|
+
- SDK clients
|
|
96
|
+
- persistence models or external API response shapes
|
|
97
|
+
- another feature-slice's internals
|
|
98
|
+
- domain workflow logic that bypasses the Handler
|
|
99
|
+
|
|
100
|
+
Allowed flow:
|
|
101
|
+
|
|
102
|
+
```txt
|
|
103
|
+
entrypoint / framework adapter -> Command -> Handler / dispatcher -> Ports -> infrastructure adapters
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Forbidden flow:
|
|
107
|
+
|
|
108
|
+
```txt
|
|
109
|
+
entrypoint / framework adapter -> infrastructure / database / SDK / repository implementation
|
|
110
|
+
entrypoint / framework adapter -> domain workflow internals that bypass the Handler
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
If dependency wiring needs infrastructure implementations, prefer a composition/bootstrap module or small factory that constructs the Handler. Keep request handling, command creation, and result translation separate from infrastructure behavior.
|
|
114
|
+
|
|
84
115
|
---
|
|
85
116
|
|
|
86
117
|
## 4. Implementation Workflow
|
|
@@ -95,6 +95,34 @@ This means:
|
|
|
95
95
|
|
|
96
96
|
If business logic needs a DB client, SDK response, HTTP object, or framework context directly, the boundary is probably wrong.
|
|
97
97
|
|
|
98
|
+
## Framework adapter dependency rule
|
|
99
|
+
|
|
100
|
+
Framework code is a driving adapter. Examples include HTTP routes, controllers, Next.js App Router files, server actions, CLI commands, queue consumers, jobs, webhooks, RPC handlers, and GraphQL resolvers.
|
|
101
|
+
|
|
102
|
+
Framework adapters may adapt framework input/output and call the application/orchestration boundary. They must not directly import or call:
|
|
103
|
+
|
|
104
|
+
- repository implementations or database clients
|
|
105
|
+
- SDK clients or infrastructure adapters
|
|
106
|
+
- persistence models or external API response shapes
|
|
107
|
+
- domain internals that perform a business workflow outside an application use case
|
|
108
|
+
- other delivery/framework adapters
|
|
109
|
+
|
|
110
|
+
Allowed flow:
|
|
111
|
+
|
|
112
|
+
```txt
|
|
113
|
+
framework adapter -> application use case / orchestration API -> domain + ports
|
|
114
|
+
infrastructure adapter -> application/domain port contracts
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Forbidden flow:
|
|
118
|
+
|
|
119
|
+
```txt
|
|
120
|
+
framework adapter -> infrastructure / database / SDK / repository implementation
|
|
121
|
+
framework adapter -> domain workflow internals that bypass the application boundary
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
When planning or implementing a feature, name the application/orchestration API each framework entrypoint is allowed to call. Add an explicit allow/deny import list when the boundary could be ambiguous.
|
|
125
|
+
|
|
98
126
|
## Domain modeling: entity, value object, or neither
|
|
99
127
|
|
|
100
128
|
Do not force DDD labels onto every concept. Use them only when they buy clarity, express real business meaning, or protect invariants.
|
|
@@ -283,6 +283,31 @@ When shaping a feature brief, prefer:
|
|
|
283
283
|
7. measurable success signals
|
|
284
284
|
8. non-technical acceptance criteria
|
|
285
285
|
|
|
286
|
+
## Optional Notion export after local write
|
|
287
|
+
|
|
288
|
+
After the local Markdown file is written successfully, optionally offer Notion export. Local Markdown remains the canonical pipeline artifact and Notion is only a convenience export destination.
|
|
289
|
+
|
|
290
|
+
1. Do not check Notion export before the local file exists.
|
|
291
|
+
2. After writing the local file, read `.sibu/state.json` if available.
|
|
292
|
+
3. Offer export only when all are true:
|
|
293
|
+
- `selectedMcpServers` includes `notion`
|
|
294
|
+
- `mcpServerConfigs.notion.docsParentPage` is present
|
|
295
|
+
- Notion MCP tools are available in the current agent session
|
|
296
|
+
4. If export is unavailable, do nothing else and finish with the normal local path response.
|
|
297
|
+
5. If export is available, ask for explicit opt-in before creating or modifying any Notion page.
|
|
298
|
+
6. If the user declines, do nothing else.
|
|
299
|
+
7. If the user accepts, create or reuse Notion organization pages under the configured parent page:
|
|
300
|
+
|
|
301
|
+
```txt
|
|
302
|
+
<docsParentPage>
|
|
303
|
+
└── <repo name>
|
|
304
|
+
└── Features
|
|
305
|
+
└── <feature name>
|
|
306
|
+
└── Feature Brief
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Create a new document page for the just-written artifact content. Do not write Notion URLs back into local Markdown. Report Notion export success or a clear Notion export failure, while preserving the local file as the completed artifact either way.
|
|
310
|
+
|
|
286
311
|
## Final response behavior
|
|
287
312
|
|
|
288
313
|
After writing the file, final-answer with only the path created or updated. Do not paste the feature brief body, excerpt, outline, or section summaries.
|
|
@@ -44,9 +44,10 @@ Add `"use client"` only for code that needs client-side capabilities, such as:
|
|
|
44
44
|
Prefer isolating the smallest interactive subtree into a Client Component rather than turning a whole page or layout into a Client Component.
|
|
45
45
|
|
|
46
46
|
### 4. Keep `src/app/**` thin
|
|
47
|
-
- Treat `src/app/**` as a framework boundary.
|
|
48
|
-
-
|
|
49
|
-
-
|
|
47
|
+
- Treat `src/app/**` as a framework adapter boundary.
|
|
48
|
+
- When an architecture skill or technical design defines an orchestration/application boundary, App Router files may call only that boundary.
|
|
49
|
+
- Pages, layouts, route handlers, Server Actions, and metadata functions must not bypass the selected architecture's dependency rules.
|
|
50
|
+
- Keep request parsing, response formatting, redirects, rendering decisions, and framework concerns in `src/app/**`.
|
|
50
51
|
- Move reusable business behavior out of App Router files.
|
|
51
52
|
|
|
52
53
|
### 5. Route handlers are framework adapters
|
|
@@ -54,6 +55,7 @@ Prefer isolating the smallest interactive subtree into a Client Component rather
|
|
|
54
55
|
- Use the Web `Request` and `Response` APIs.
|
|
55
56
|
- Keep handlers focused on HTTP concerns: parse input, call application behavior, and return a stable response.
|
|
56
57
|
- Do not put backend business rules directly in route handlers.
|
|
58
|
+
- Do not import infrastructure, database clients, repository implementations, SDK wrappers, persistence models, or external API shapes directly from App Router files unless the selected architecture explicitly allows it.
|
|
57
59
|
|
|
58
60
|
### 6. Use Next.js error and empty-state conventions
|
|
59
61
|
- Use `notFound()` for route resources that genuinely do not exist.
|
|
@@ -72,6 +72,8 @@ Translate product intent into implementation direction.
|
|
|
72
72
|
|
|
73
73
|
Deep Modules answer “where does this implementation work belong?” Architecture guidance answers “how is that module structured internally?” Translate the feature brief's selected Deep Modules into implementation boundaries appropriate for the selected architecture. Capture those boundaries in the technical design so downstream Scrum planning, implementation planning, and execution can trust the technical design instead of rereading the Deep Module Map by default.
|
|
74
74
|
|
|
75
|
+
When a feature crosses a framework or delivery boundary, include the allowed orchestration/application entrypoint and the forbidden lower-level dependencies. Keep this framework-agnostic: name roles like framework adapter, application/orchestration boundary, domain, port, and infrastructure, then add concrete project paths only where useful.
|
|
76
|
+
|
|
75
77
|
Prefer:
|
|
76
78
|
|
|
77
79
|
- concise decisions over long explanation
|
|
@@ -143,6 +145,8 @@ Use this structure as a starting point. Delete sections that do not add value.
|
|
|
143
145
|
|
|
144
146
|
<Explain how the selected Deep Modules translate into architecture, module, command, file, or implementation boundaries when that affects downstream work.>
|
|
145
147
|
|
|
148
|
+
<For framework/delivery entrypoints, state the application/orchestration API they may call and the lower-level layers, modules, or paths they must not call directly.>
|
|
149
|
+
|
|
146
150
|
## Validation
|
|
147
151
|
<Focused test/build/manual checks.>
|
|
148
152
|
|
|
@@ -154,6 +158,31 @@ Use this structure as a starting point. Delete sections that do not add value.
|
|
|
154
158
|
|
|
155
159
|
A good technical design is short, specific, and useful. It should not try to be the product brief, architecture skill, clean-code skill, implementation plan, or ticket backlog.
|
|
156
160
|
|
|
161
|
+
## Optional Notion export after local write
|
|
162
|
+
|
|
163
|
+
After the local Markdown file is written successfully, optionally offer Notion export. Local Markdown remains the canonical pipeline artifact and Notion is only a convenience export destination.
|
|
164
|
+
|
|
165
|
+
1. Do not check Notion export before the local file exists.
|
|
166
|
+
2. After writing the local file, read `.sibu/state.json` if available.
|
|
167
|
+
3. Offer export only when all are true:
|
|
168
|
+
- `selectedMcpServers` includes `notion`
|
|
169
|
+
- `mcpServerConfigs.notion.docsParentPage` is present
|
|
170
|
+
- Notion MCP tools are available in the current agent session
|
|
171
|
+
4. If export is unavailable, do nothing else and finish with the normal local path response.
|
|
172
|
+
5. If export is available, ask for explicit opt-in before creating or modifying any Notion page.
|
|
173
|
+
6. If the user declines, do nothing else.
|
|
174
|
+
7. If the user accepts, create or reuse Notion organization pages under the configured parent page:
|
|
175
|
+
|
|
176
|
+
```txt
|
|
177
|
+
<docsParentPage>
|
|
178
|
+
└── <repo name>
|
|
179
|
+
└── Features
|
|
180
|
+
└── <feature name>
|
|
181
|
+
└── Technical Design
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Create a new document page for the just-written artifact content. Do not write Notion URLs back into local Markdown. Report Notion export success or a clear Notion export failure, while preserving the local file as the completed artifact either way.
|
|
185
|
+
|
|
157
186
|
## Final response behavior
|
|
158
187
|
|
|
159
188
|
After writing the file, final-answer with only the path created or updated. Do not paste the technical design body, excerpt, outline, or section summaries.
|
|
@@ -118,6 +118,31 @@ Use only helpful sections from this shape:
|
|
|
118
118
|
|
|
119
119
|
The Binding Mockups section is authoritative for downstream work unless this UX spec is revised.
|
|
120
120
|
|
|
121
|
+
## Optional Notion export after local write
|
|
122
|
+
|
|
123
|
+
After the local Markdown file is written successfully, optionally offer Notion export. Local Markdown remains the canonical pipeline artifact and Notion is only a convenience export destination.
|
|
124
|
+
|
|
125
|
+
1. Do not check Notion export before the local file exists.
|
|
126
|
+
2. After writing the local file, read `.sibu/state.json` if available.
|
|
127
|
+
3. Offer export only when all are true:
|
|
128
|
+
- `selectedMcpServers` includes `notion`
|
|
129
|
+
- `mcpServerConfigs.notion.docsParentPage` is present
|
|
130
|
+
- Notion MCP tools are available in the current agent session
|
|
131
|
+
4. If export is unavailable, do nothing else and finish with the normal local path response.
|
|
132
|
+
5. If export is available, ask for explicit opt-in before creating or modifying any Notion page.
|
|
133
|
+
6. If the user declines, do nothing else.
|
|
134
|
+
7. If the user accepts, create or reuse Notion organization pages under the configured parent page:
|
|
135
|
+
|
|
136
|
+
```txt
|
|
137
|
+
<docsParentPage>
|
|
138
|
+
└── <repo name>
|
|
139
|
+
└── Features
|
|
140
|
+
└── <feature name>
|
|
141
|
+
└── UX Design
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Create a new document page for the just-written artifact content. Do not write Notion URLs back into local Markdown. Report Notion export success or a clear Notion export failure, while preserving the local file as the completed artifact either way.
|
|
145
|
+
|
|
121
146
|
## Final response behavior
|
|
122
147
|
|
|
123
148
|
After writing the file, final-answer with only the path created or updated. Do not paste the UX spec body, excerpt, outline, mockups, or section summaries.
|