mdboard 1.2.0 → 2.0.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.js +130 -44
- package/index.html +3321 -1195
- package/package.json +10 -11
- package/presets/kanban/api.json +91 -0
- package/presets/kanban/cli.json +69 -0
- package/presets/kanban/docs.json +29 -0
- package/presets/kanban/entities.json +128 -0
- package/presets/kanban/structure.json +15 -0
- package/presets/kanban/ui.json +86 -0
- package/presets/scrum/api.json +98 -0
- package/presets/scrum/cli.json +120 -0
- package/presets/scrum/docs.json +43 -0
- package/presets/scrum/entities.json +268 -0
- package/presets/scrum/structure.json +32 -0
- package/presets/scrum/ui.json +201 -0
- package/presets/shape-up/api.json +40 -0
- package/presets/shape-up/cli.json +44 -0
- package/presets/shape-up/docs.json +32 -0
- package/presets/shape-up/entities.json +140 -0
- package/presets/shape-up/structure.json +28 -0
- package/presets/shape-up/ui.json +114 -0
- package/src/cli/cli.js +338 -0
- package/src/cli/config.js +234 -0
- package/src/cli/init.js +175 -0
- package/src/cli/preset.js +849 -0
- package/src/cli/skill.js +417 -0
- package/src/cli/status.js +180 -0
- package/src/core/config.js +551 -0
- package/src/core/history.js +146 -0
- package/src/core/scanner.js +521 -0
- package/{workspace.js → src/core/workspace.js} +0 -15
- package/{yaml.js → src/core/yaml.js} +5 -1
- package/src/server/api.js +616 -0
- package/{server.js → src/server/server.js} +180 -132
- package/{watcher.js → src/server/watcher.js} +40 -9
- package/api.js +0 -752
- package/config.js +0 -73
- package/defaults.json +0 -43
- package/init.js +0 -109
- package/scanner.js +0 -491
package/config.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* mdboard — Configuration loader
|
|
3
|
-
*
|
|
4
|
-
* Resolution order (highest priority first):
|
|
5
|
-
* 1. Explicit path via --config / MDBOARD_CONFIG
|
|
6
|
-
* 2. <projectDir>/project/mdboard.json (per-project)
|
|
7
|
-
* 3. <projectDir>/mdboard.json (workspace)
|
|
8
|
-
* 4. ~/.config/mdboard/mdboard.json (global)
|
|
9
|
-
* 5. defaults.json (built-in)
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const fs = require('fs');
|
|
13
|
-
const path = require('path');
|
|
14
|
-
const os = require('os');
|
|
15
|
-
|
|
16
|
-
const defaults = require('./defaults.json');
|
|
17
|
-
|
|
18
|
-
function deepMerge(target, source) {
|
|
19
|
-
const result = { ...target };
|
|
20
|
-
for (const key of Object.keys(source)) {
|
|
21
|
-
const sv = source[key];
|
|
22
|
-
const tv = target[key];
|
|
23
|
-
if (sv && typeof sv === 'object' && !Array.isArray(sv) && tv && typeof tv === 'object' && !Array.isArray(tv)) {
|
|
24
|
-
result[key] = deepMerge(tv, sv);
|
|
25
|
-
} else {
|
|
26
|
-
result[key] = sv;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return result;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function tryReadJson(filePath) {
|
|
33
|
-
try {
|
|
34
|
-
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
35
|
-
return JSON.parse(raw);
|
|
36
|
-
} catch {
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function loadConfig(projectDir, explicitPath) {
|
|
42
|
-
const candidates = [];
|
|
43
|
-
|
|
44
|
-
if (explicitPath) {
|
|
45
|
-
candidates.push(path.resolve(explicitPath));
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (projectDir) {
|
|
49
|
-
candidates.push(path.join(projectDir, 'project', 'mdboard.json'));
|
|
50
|
-
candidates.push(path.join(projectDir, 'mdboard.json'));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const globalPath = path.join(os.homedir(), '.config', 'mdboard', 'mdboard.json');
|
|
54
|
-
candidates.push(globalPath);
|
|
55
|
-
|
|
56
|
-
let userConfig = null;
|
|
57
|
-
let configPath = null;
|
|
58
|
-
|
|
59
|
-
for (const p of candidates) {
|
|
60
|
-
const data = tryReadJson(p);
|
|
61
|
-
if (data) {
|
|
62
|
-
userConfig = data;
|
|
63
|
-
configPath = p;
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const config = userConfig ? deepMerge(defaults, userConfig) : { ...defaults };
|
|
69
|
-
config._path = configPath;
|
|
70
|
-
return config;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
module.exports = { loadConfig, deepMerge };
|
package/defaults.json
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"entities": {
|
|
3
|
-
"milestone": { "singular": "Milestone", "plural": "Milestones", "dir": "milestones" },
|
|
4
|
-
"epic": { "singular": "Epic", "plural": "Epics", "dir": "epics" },
|
|
5
|
-
"task": { "singular": "Task", "plural": "Tasks", "dir": "backlog", "prefix": "TASK", "legacyPrefixes": ["FEAT"] },
|
|
6
|
-
"sprint": { "singular": "Sprint", "plural": "Sprints", "dir": "sprints" }
|
|
7
|
-
},
|
|
8
|
-
"statuses": {
|
|
9
|
-
"task": [
|
|
10
|
-
{ "key": "backlog", "label": "Backlog", "color": "#5A5A63", "icon": "dashed-circle" },
|
|
11
|
-
{ "key": "todo", "label": "Todo", "color": "#8B8B93", "icon": "circle" },
|
|
12
|
-
{ "key": "in-progress", "label": "In Progress", "color": "#D4A72C", "icon": "half-circle" },
|
|
13
|
-
{ "key": "in-review", "label": "In Review", "color": "#8B5CF6", "icon": "three-quarter-circle" },
|
|
14
|
-
{ "key": "done", "label": "Done", "color": "#2EA043", "icon": "check-circle" },
|
|
15
|
-
{ "key": "blocked", "label": "Blocked", "color": "#DA3633", "icon": "x-circle" },
|
|
16
|
-
{ "key": "cancelled", "label": "Cancelled", "color": "#5A5A63", "icon": "slash-circle" }
|
|
17
|
-
],
|
|
18
|
-
"milestone": [
|
|
19
|
-
{ "key": "planned", "label": "Planned", "color": "#8B8B93" },
|
|
20
|
-
{ "key": "active", "label": "Active", "color": "#5B6EF5" },
|
|
21
|
-
{ "key": "completed", "label": "Completed", "color": "#2EA043" }
|
|
22
|
-
],
|
|
23
|
-
"epic": [
|
|
24
|
-
{ "key": "active", "label": "Active", "color": "#5B6EF5" },
|
|
25
|
-
{ "key": "completed", "label": "Completed", "color": "#2EA043" },
|
|
26
|
-
{ "key": "blocked", "label": "Blocked", "color": "#DA3633" }
|
|
27
|
-
],
|
|
28
|
-
"sprint": [
|
|
29
|
-
{ "key": "planned", "label": "Planned", "color": "#8B8B93" },
|
|
30
|
-
{ "key": "active", "label": "Active", "color": "#5B6EF5" },
|
|
31
|
-
{ "key": "completed", "label": "Completed", "color": "#2EA043" },
|
|
32
|
-
{ "key": "cancelled", "label": "Cancelled", "color": "#DA3633" }
|
|
33
|
-
]
|
|
34
|
-
},
|
|
35
|
-
"boardColumns": ["backlog", "todo", "in-progress", "in-review", "done"],
|
|
36
|
-
"priorities": [
|
|
37
|
-
{ "key": "urgent", "label": "Urgent", "color": "#F97316", "bars": 4 },
|
|
38
|
-
{ "key": "high", "label": "High", "color": "#F97316", "bars": 3 },
|
|
39
|
-
{ "key": "medium", "label": "Medium", "color": "#D4A72C", "bars": 2 },
|
|
40
|
-
{ "key": "low", "label": "Low", "color": "#5B6EF5", "bars": 1 }
|
|
41
|
-
],
|
|
42
|
-
"completedStatus": "done"
|
|
43
|
-
}
|
package/init.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const { loadConfig } = require('./config');
|
|
6
|
-
|
|
7
|
-
const cwd = process.cwd();
|
|
8
|
-
const projectPath = path.join(cwd, 'project');
|
|
9
|
-
const projectName = path.basename(cwd);
|
|
10
|
-
const today = new Date().toISOString().split('T')[0];
|
|
11
|
-
const config = loadConfig(cwd);
|
|
12
|
-
|
|
13
|
-
if (fs.existsSync(projectPath)) {
|
|
14
|
-
console.log(`\n project/ already exists at ${projectPath}`);
|
|
15
|
-
console.log(' Skipping init to avoid overwriting existing data.\n');
|
|
16
|
-
process.exit(0);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const msDir = config.entities.milestone.dir;
|
|
20
|
-
|
|
21
|
-
// Create directories
|
|
22
|
-
fs.mkdirSync(projectPath, { recursive: true });
|
|
23
|
-
fs.mkdirSync(path.join(projectPath, msDir), { recursive: true });
|
|
24
|
-
fs.mkdirSync(path.join(projectPath, 'archive'), { recursive: true });
|
|
25
|
-
|
|
26
|
-
// PROJECT.md
|
|
27
|
-
fs.writeFileSync(path.join(projectPath, 'PROJECT.md'), `---
|
|
28
|
-
name: "${projectName}"
|
|
29
|
-
description: ""
|
|
30
|
-
created: ${today}
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
# ${projectName}
|
|
34
|
-
|
|
35
|
-
## Current State
|
|
36
|
-
|
|
37
|
-
No milestones or sprints created yet.
|
|
38
|
-
|
|
39
|
-
## Notes
|
|
40
|
-
|
|
41
|
-
`, 'utf-8');
|
|
42
|
-
|
|
43
|
-
// metrics.md
|
|
44
|
-
fs.writeFileSync(path.join(projectPath, 'metrics.md'), `---
|
|
45
|
-
updated: ${today}
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
# Metrics
|
|
49
|
-
|
|
50
|
-
## Velocity
|
|
51
|
-
|
|
52
|
-
| Sprint | Planned | Completed | Rate |
|
|
53
|
-
|--------|---------|-----------|------|
|
|
54
|
-
|
|
55
|
-
## Notes
|
|
56
|
-
|
|
57
|
-
`, 'utf-8');
|
|
58
|
-
|
|
59
|
-
// mdboard.json — example config
|
|
60
|
-
fs.writeFileSync(path.join(projectPath, 'mdboard.json'), `{
|
|
61
|
-
"entities": {
|
|
62
|
-
"task": {
|
|
63
|
-
"singular": "Task",
|
|
64
|
-
"plural": "Tasks",
|
|
65
|
-
"prefix": "TASK"
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
`, 'utf-8');
|
|
70
|
-
|
|
71
|
-
// mdboard.css — example custom theme
|
|
72
|
-
fs.writeFileSync(path.join(projectPath, 'mdboard.css'), `/* mdboard custom theme
|
|
73
|
-
Override any CSS variable from the dashboard.
|
|
74
|
-
Example:
|
|
75
|
-
:root {
|
|
76
|
-
--bg: #FFFFFF;
|
|
77
|
-
--surface: #F8F9FA;
|
|
78
|
-
--text: #212529;
|
|
79
|
-
--accent: #0969DA;
|
|
80
|
-
}
|
|
81
|
-
*/
|
|
82
|
-
`, 'utf-8');
|
|
83
|
-
|
|
84
|
-
console.log(`
|
|
85
|
-
mdboard init — project scaffolded
|
|
86
|
-
|
|
87
|
-
Created:
|
|
88
|
-
project/PROJECT.md
|
|
89
|
-
project/metrics.md
|
|
90
|
-
project/${msDir}/
|
|
91
|
-
project/archive/
|
|
92
|
-
project/mdboard.json
|
|
93
|
-
project/mdboard.css
|
|
94
|
-
|
|
95
|
-
Next steps:
|
|
96
|
-
1. Edit project/PROJECT.md with your project details
|
|
97
|
-
2. Create milestones and epics under project/${msDir}/
|
|
98
|
-
3. Customize project/mdboard.json for your workflow
|
|
99
|
-
4. Run \`mdboard\` to start the dashboard
|
|
100
|
-
|
|
101
|
-
Multi-repo workspace:
|
|
102
|
-
Create a workspace.json to manage multiple repos:
|
|
103
|
-
{
|
|
104
|
-
"sources": [
|
|
105
|
-
{ "name": "api", "path": "../api-repo", "icon": "🔧" },
|
|
106
|
-
{ "name": "web", "path": "../web-repo", "icon": "🌐" }
|
|
107
|
-
]
|
|
108
|
-
}
|
|
109
|
-
`);
|