@geminilight/mindos 0.6.28 → 0.6.30
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 +10 -4
- package/app/app/api/a2a/agents/route.ts +9 -0
- package/app/app/api/a2a/delegations/route.ts +9 -0
- package/app/app/api/a2a/discover/route.ts +2 -0
- package/app/app/api/a2a/route.ts +6 -6
- package/app/app/api/acp/config/route.ts +82 -0
- package/app/app/api/acp/detect/route.ts +114 -0
- package/app/app/api/acp/install/route.ts +51 -0
- package/app/app/api/acp/registry/route.ts +31 -0
- package/app/app/api/acp/session/route.ts +185 -0
- package/app/app/api/ask/route.ts +116 -13
- package/app/app/api/workflows/route.ts +156 -0
- package/app/app/layout.tsx +2 -0
- package/app/app/page.tsx +7 -2
- package/app/components/ActivityBar.tsx +12 -4
- package/app/components/AskModal.tsx +4 -1
- package/app/components/DirView.tsx +64 -2
- package/app/components/FileTree.tsx +40 -10
- package/app/components/GuideCard.tsx +7 -17
- package/app/components/HomeContent.tsx +1 -0
- package/app/components/MarkdownView.tsx +2 -0
- package/app/components/Panel.tsx +1 -0
- package/app/components/RightAskPanel.tsx +5 -1
- package/app/components/SearchModal.tsx +234 -80
- package/app/components/SidebarLayout.tsx +6 -0
- package/app/components/agents/AgentDetailContent.tsx +266 -52
- package/app/components/agents/AgentsContentPage.tsx +32 -6
- package/app/components/agents/AgentsPanelA2aTab.tsx +684 -0
- package/app/components/agents/AgentsPanelSessionsTab.tsx +166 -0
- package/app/components/agents/SkillDetailPopover.tsx +4 -9
- package/app/components/agents/agents-content-model.ts +2 -2
- package/app/components/ask/AgentSelectorCapsule.tsx +218 -0
- package/app/components/ask/AskContent.tsx +197 -239
- package/app/components/ask/FileChip.tsx +82 -17
- package/app/components/ask/MentionPopover.tsx +21 -3
- package/app/components/ask/MessageList.tsx +30 -9
- package/app/components/ask/SlashCommandPopover.tsx +21 -3
- package/app/components/help/HelpContent.tsx +9 -9
- package/app/components/panels/AgentsPanel.tsx +2 -0
- package/app/components/panels/AgentsPanelAgentDetail.tsx +5 -8
- package/app/components/panels/AgentsPanelHubNav.tsx +16 -2
- package/app/components/panels/EchoPanel.tsx +5 -1
- package/app/components/panels/EchoSidebarStats.tsx +136 -0
- package/app/components/panels/WorkflowsPanel.tsx +206 -0
- package/app/components/renderers/workflow-yaml/StepEditor.tsx +157 -0
- package/app/components/renderers/workflow-yaml/WorkflowEditor.tsx +201 -0
- package/app/components/renderers/workflow-yaml/WorkflowRunner.tsx +226 -0
- package/app/components/renderers/workflow-yaml/WorkflowYamlRenderer.tsx +126 -0
- package/app/components/renderers/workflow-yaml/execution.ts +177 -0
- package/app/components/renderers/workflow-yaml/index.ts +6 -0
- package/app/components/renderers/workflow-yaml/manifest.ts +21 -0
- package/app/components/renderers/workflow-yaml/parser.ts +172 -0
- package/app/components/renderers/workflow-yaml/selectors.tsx +522 -0
- package/app/components/renderers/workflow-yaml/serializer.ts +56 -0
- package/app/components/renderers/workflow-yaml/types.ts +46 -0
- package/app/components/settings/KnowledgeTab.tsx +3 -6
- package/app/components/settings/McpSkillsSection.tsx +4 -5
- package/app/components/settings/McpTab.tsx +6 -8
- package/app/components/setup/StepSecurity.tsx +4 -5
- package/app/components/setup/index.tsx +5 -11
- package/app/components/ui/Toaster.tsx +39 -0
- package/app/hooks/useA2aRegistry.ts +6 -1
- package/app/hooks/useAcpConfig.ts +96 -0
- package/app/hooks/useAcpDetection.ts +120 -0
- package/app/hooks/useAcpRegistry.ts +86 -0
- package/app/hooks/useAskModal.ts +12 -5
- package/app/hooks/useAskPanel.ts +8 -5
- package/app/hooks/useAskSession.ts +19 -2
- package/app/hooks/useDelegationHistory.ts +49 -0
- package/app/hooks/useImageUpload.ts +152 -0
- package/app/lib/a2a/client.ts +49 -5
- package/app/lib/a2a/orchestrator.ts +0 -1
- package/app/lib/a2a/task-handler.ts +4 -4
- package/app/lib/a2a/types.ts +15 -0
- package/app/lib/acp/acp-tools.ts +95 -0
- package/app/lib/acp/agent-descriptors.ts +274 -0
- package/app/lib/acp/bridge.ts +144 -0
- package/app/lib/acp/index.ts +40 -0
- package/app/lib/acp/registry.ts +202 -0
- package/app/lib/acp/session.ts +717 -0
- package/app/lib/acp/subprocess.ts +495 -0
- package/app/lib/acp/types.ts +274 -0
- package/app/lib/agent/model.ts +18 -3
- package/app/lib/agent/to-agent-messages.ts +25 -2
- package/app/lib/agent/tools.ts +2 -1
- package/app/lib/i18n/_core.ts +22 -0
- package/app/lib/i18n/index.ts +35 -0
- package/app/lib/i18n/modules/ai-chat.ts +215 -0
- package/app/lib/i18n/modules/common.ts +71 -0
- package/app/lib/i18n/modules/features.ts +153 -0
- package/app/lib/i18n/modules/knowledge.ts +429 -0
- package/app/lib/i18n/modules/navigation.ts +153 -0
- package/app/lib/i18n/modules/onboarding.ts +523 -0
- package/app/lib/i18n/modules/panels.ts +1196 -0
- package/app/lib/i18n/modules/settings.ts +585 -0
- package/app/lib/i18n-en.ts +2 -1518
- package/app/lib/i18n-zh.ts +2 -1542
- package/app/lib/i18n.ts +3 -6
- package/app/lib/pi-integration/skills.ts +21 -6
- package/app/lib/renderers/index.ts +2 -2
- package/app/lib/settings.ts +10 -0
- package/app/lib/toast.ts +79 -0
- package/app/lib/types.ts +12 -1
- package/app/next-env.d.ts +1 -1
- package/app/package.json +3 -1
- package/bin/cli.js +25 -25
- package/bin/commands/file.js +29 -2
- package/bin/commands/space.js +249 -91
- package/package.json +1 -1
- package/templates/en/.mindos/workflows/Sprint Release.flow.yaml +130 -0
- package/templates/zh/.mindos/workflows//345/221/250/350/277/255/344/273/243/346/243/200/346/237/245.flow.yaml +84 -0
- package/app/components/renderers/workflow/WorkflowRenderer.tsx +0 -409
- package/app/components/renderers/workflow/manifest.ts +0 -14
package/bin/commands/space.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* mindos space —
|
|
2
|
+
* mindos space — Knowledge base structure management
|
|
3
|
+
*
|
|
4
|
+
* Manages the directory tree of the knowledge base.
|
|
5
|
+
* "Space" = directory + INSTRUCTION.md (AI context).
|
|
6
|
+
* All directory operations go here; file content ops go to `mindos file`.
|
|
3
7
|
*/
|
|
4
8
|
|
|
5
9
|
import { existsSync, readdirSync, statSync, mkdirSync, writeFileSync, rmSync, renameSync } from 'node:fs';
|
|
6
|
-
import { resolve,
|
|
7
|
-
import { bold, dim, cyan, green, red } from '../lib/colors.js';
|
|
10
|
+
import { resolve, basename } from 'node:path';
|
|
11
|
+
import { bold, dim, cyan, green, red, yellow } from '../lib/colors.js';
|
|
8
12
|
import { loadConfig } from '../lib/config.js';
|
|
9
13
|
import { output, isJsonMode, EXIT } from '../lib/command.js';
|
|
10
14
|
|
|
@@ -21,15 +25,18 @@ function getMindRoot() {
|
|
|
21
25
|
export const meta = {
|
|
22
26
|
name: 'space',
|
|
23
27
|
group: 'Knowledge',
|
|
24
|
-
summary: '
|
|
28
|
+
summary: 'Knowledge base structure (ls, mkdir, rmdir, init, info, tree)',
|
|
25
29
|
usage: 'mindos space <subcommand>',
|
|
26
30
|
examples: [
|
|
27
|
-
'mindos space
|
|
28
|
-
'mindos space
|
|
31
|
+
'mindos space ls',
|
|
32
|
+
'mindos space ls "📝 笔记"',
|
|
33
|
+
'mindos space tree',
|
|
34
|
+
'mindos space mkdir "📝 笔记/新分类"',
|
|
35
|
+
'mindos space rmdir "📝 笔记/旧分类"',
|
|
36
|
+
'mindos space init "exploration"',
|
|
37
|
+
'mindos space info "📝 笔记"',
|
|
29
38
|
'mindos space create "Research"',
|
|
30
|
-
'mindos space delete "Old Project"',
|
|
31
39
|
'mindos space rename "Old" "New"',
|
|
32
|
-
'mindos space info "Work"',
|
|
33
40
|
],
|
|
34
41
|
};
|
|
35
42
|
|
|
@@ -39,48 +46,56 @@ export async function run(args, flags) {
|
|
|
39
46
|
|
|
40
47
|
if (!sub || flags.help || flags.h) {
|
|
41
48
|
console.log(`
|
|
42
|
-
${bold('mindos space')} —
|
|
49
|
+
${bold('mindos space')} — Knowledge base structure management
|
|
43
50
|
|
|
44
|
-
${bold('
|
|
45
|
-
${cyan('
|
|
46
|
-
${cyan('
|
|
47
|
-
${cyan('
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
${bold('Browse:')}
|
|
52
|
+
${cyan('ls [path]'.padEnd(24))}${dim('List contents of a directory (default: root)')}
|
|
53
|
+
${cyan('tree [path]'.padEnd(24))}${dim('Show directory tree recursively')}
|
|
54
|
+
${cyan('info <path>'.padEnd(24))}${dim('Show directory details (type, files, modified)')}
|
|
55
|
+
|
|
56
|
+
${bold('Structure:')}
|
|
57
|
+
${cyan('create <name>'.padEnd(24))}${dim('Create a new Space (directory + INSTRUCTION.md)')}
|
|
58
|
+
${cyan('mkdir <path>'.padEnd(24))}${dim('Create a directory (no INSTRUCTION.md)')}
|
|
59
|
+
${cyan('rmdir <path>'.padEnd(24))}${dim('Delete a directory and all its contents')}
|
|
60
|
+
${cyan('rename <old> <new>'.padEnd(24))}${dim('Rename or move a directory')}
|
|
61
|
+
${cyan('init <path>'.padEnd(24))}${dim('Upgrade a directory to a Space (add INSTRUCTION.md)')}
|
|
50
62
|
|
|
51
63
|
${bold('Examples:')}
|
|
52
|
-
${dim('mindos space
|
|
53
|
-
${dim('mindos space
|
|
54
|
-
${dim('mindos space
|
|
55
|
-
${dim('mindos space
|
|
64
|
+
${dim('mindos space ls')}
|
|
65
|
+
${dim('mindos space ls "📝 笔记" --json')}
|
|
66
|
+
${dim('mindos space tree "⚙️ 配置"')}
|
|
67
|
+
${dim('mindos space mkdir "📝 笔记/新分类/子分类"')}
|
|
68
|
+
${dim('mindos space init "exploration"')}
|
|
56
69
|
`);
|
|
57
70
|
return;
|
|
58
71
|
}
|
|
59
72
|
|
|
60
73
|
switch (sub) {
|
|
61
|
-
case 'list': return
|
|
62
|
-
case '
|
|
74
|
+
case 'ls': case 'list': return spaceLs(root, args[1], flags);
|
|
75
|
+
case 'tree': return spaceTree(root, args[1], flags);
|
|
76
|
+
case 'info': return spaceInfo(root, args[1], flags);
|
|
63
77
|
case 'create': return spaceCreate(root, args[1], flags);
|
|
64
|
-
case '
|
|
78
|
+
case 'mkdir': return spaceMkdir(root, args[1], flags);
|
|
79
|
+
case 'rmdir': case 'rm': case 'delete': return spaceRmdir(root, args[1], flags);
|
|
65
80
|
case 'rename': case 'mv': return spaceRename(root, args[1], args[2], flags);
|
|
66
|
-
case '
|
|
81
|
+
case 'init': case 'convert': return spaceInit(root, args[1], flags);
|
|
67
82
|
default:
|
|
68
83
|
console.error(red(`Unknown subcommand: ${sub}`));
|
|
69
|
-
console.error(dim('Available:
|
|
70
|
-
process.exit(EXIT.
|
|
84
|
+
console.error(dim('Available: ls, tree, info, create, mkdir, rmdir, rename, init'));
|
|
85
|
+
process.exit(EXIT.ARGS);
|
|
71
86
|
}
|
|
72
87
|
}
|
|
73
88
|
|
|
89
|
+
// ── Helpers ────────────────────────────────────────────────────────────────────
|
|
90
|
+
|
|
74
91
|
function isSpace(dir) {
|
|
75
|
-
// A space is a top-level directory that contains an INSTRUCTION.md
|
|
76
92
|
return existsSync(resolve(dir, 'INSTRUCTION.md'));
|
|
77
93
|
}
|
|
78
94
|
|
|
79
95
|
function countFiles(dir) {
|
|
80
96
|
let count = 0;
|
|
81
97
|
try {
|
|
82
|
-
const
|
|
83
|
-
for (const e of entries) {
|
|
98
|
+
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
84
99
|
if (e.name.startsWith('.')) continue;
|
|
85
100
|
if (e.isFile()) count++;
|
|
86
101
|
else if (e.isDirectory()) count += countFiles(resolve(dir, e.name));
|
|
@@ -89,133 +104,276 @@ function countFiles(dir) {
|
|
|
89
104
|
return count;
|
|
90
105
|
}
|
|
91
106
|
|
|
92
|
-
function
|
|
93
|
-
const
|
|
107
|
+
function resolvePath(root, relPath) {
|
|
108
|
+
const full = relPath ? resolve(root, relPath) : root;
|
|
109
|
+
if (!existsSync(full)) {
|
|
110
|
+
console.error(red(`Not found: ${relPath || '(root)'}`));
|
|
111
|
+
process.exit(EXIT.NOT_FOUND);
|
|
112
|
+
}
|
|
113
|
+
return full;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ── ls: list contents of a directory ──────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
function spaceLs(root, relPath, flags) {
|
|
119
|
+
const dir = resolvePath(root, relPath);
|
|
120
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
94
121
|
const spaces = [];
|
|
122
|
+
const dirs = [];
|
|
123
|
+
const files = [];
|
|
95
124
|
|
|
96
125
|
for (const e of entries) {
|
|
97
|
-
if (
|
|
98
|
-
const full = resolve(
|
|
99
|
-
if (
|
|
100
|
-
const
|
|
101
|
-
|
|
126
|
+
if (e.name.startsWith('.')) continue;
|
|
127
|
+
const full = resolve(dir, e.name);
|
|
128
|
+
if (e.isDirectory()) {
|
|
129
|
+
const entry = { name: e.name, type: isSpace(full) ? 'space' : 'dir', fileCount: countFiles(full) };
|
|
130
|
+
(entry.type === 'space' ? spaces : dirs).push(entry);
|
|
131
|
+
} else if (e.isFile()) {
|
|
132
|
+
files.push({ name: e.name, type: 'file' });
|
|
102
133
|
}
|
|
103
134
|
}
|
|
104
135
|
|
|
105
136
|
if (isJsonMode(flags)) {
|
|
106
|
-
output({
|
|
137
|
+
output({ path: relPath || '.', entries: [...spaces, ...dirs, ...files] }, flags);
|
|
107
138
|
return;
|
|
108
139
|
}
|
|
109
140
|
|
|
110
|
-
|
|
111
|
-
|
|
141
|
+
const label = relPath ? `${relPath}/` : 'Knowledge Base';
|
|
142
|
+
const total = spaces.length + dirs.length + files.length;
|
|
143
|
+
if (total === 0) {
|
|
144
|
+
console.log(dim(`\n${label} is empty.\n`));
|
|
112
145
|
return;
|
|
113
146
|
}
|
|
114
147
|
|
|
115
|
-
console.log(`\n${bold(
|
|
148
|
+
console.log(`\n${bold(label)}\n`);
|
|
116
149
|
for (const s of spaces) {
|
|
117
|
-
console.log(` ${cyan(s.name
|
|
150
|
+
console.log(` ${cyan(s.name + '/')} ${dim(`[Space] ${s.fileCount} files`)}`);
|
|
151
|
+
}
|
|
152
|
+
for (const d of dirs) {
|
|
153
|
+
console.log(` ${d.name}/ ${dim(`${d.fileCount} files`)}`);
|
|
154
|
+
}
|
|
155
|
+
for (const f of files) {
|
|
156
|
+
console.log(` ${dim(f.name)}`);
|
|
157
|
+
}
|
|
158
|
+
if (dirs.length > 0 && !relPath) {
|
|
159
|
+
console.log(dim(`\n Tip: \`mindos space init <name>\` to upgrade a directory to a Space`));
|
|
118
160
|
}
|
|
119
161
|
console.log();
|
|
120
162
|
}
|
|
121
163
|
|
|
164
|
+
// ── tree: recursive directory tree ────────────────────────────────────────────
|
|
165
|
+
|
|
166
|
+
function spaceTree(root, relPath, flags) {
|
|
167
|
+
const dir = resolvePath(root, relPath);
|
|
168
|
+
|
|
169
|
+
if (isJsonMode(flags)) {
|
|
170
|
+
output({ path: relPath || '.', tree: buildTree(dir) }, flags);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const label = relPath || 'Knowledge Base';
|
|
175
|
+
console.log(`\n${bold(label)}`);
|
|
176
|
+
printTree(dir, '');
|
|
177
|
+
console.log();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function buildTree(dir) {
|
|
181
|
+
const result = [];
|
|
182
|
+
try {
|
|
183
|
+
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
184
|
+
if (e.name.startsWith('.')) continue;
|
|
185
|
+
const full = resolve(dir, e.name);
|
|
186
|
+
if (e.isDirectory()) {
|
|
187
|
+
result.push({ name: e.name, type: isSpace(full) ? 'space' : 'dir', children: buildTree(full) });
|
|
188
|
+
} else {
|
|
189
|
+
result.push({ name: e.name, type: 'file' });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
} catch { /* skip */ }
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function printTree(dir, prefix) {
|
|
197
|
+
let entries;
|
|
198
|
+
try { entries = readdirSync(dir, { withFileTypes: true }).filter(e => !e.name.startsWith('.')); }
|
|
199
|
+
catch { return; }
|
|
200
|
+
|
|
201
|
+
entries.forEach((e, i) => {
|
|
202
|
+
const isLast = i === entries.length - 1;
|
|
203
|
+
const connector = isLast ? '└── ' : '├── ';
|
|
204
|
+
const full = resolve(dir, e.name);
|
|
205
|
+
if (e.isDirectory()) {
|
|
206
|
+
const tag = isSpace(full) ? cyan(' [Space]') : '';
|
|
207
|
+
console.log(`${prefix}${connector}${e.name}/${tag}`);
|
|
208
|
+
printTree(full, prefix + (isLast ? ' ' : '│ '));
|
|
209
|
+
} else {
|
|
210
|
+
console.log(`${prefix}${connector}${dim(e.name)}`);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ── info ──────────────────────────────────────────────────────────────────────
|
|
216
|
+
|
|
217
|
+
function spaceInfo(root, relPath, flags) {
|
|
218
|
+
if (!relPath) {
|
|
219
|
+
console.error(red('Usage: mindos space info <path>'));
|
|
220
|
+
process.exit(EXIT.ARGS);
|
|
221
|
+
}
|
|
222
|
+
const dir = resolvePath(root, relPath);
|
|
223
|
+
const stat = statSync(dir);
|
|
224
|
+
if (!stat.isDirectory()) {
|
|
225
|
+
console.error(red(`Not a directory: ${relPath}. Use \`mindos file read\` for files.`));
|
|
226
|
+
process.exit(EXIT.ARGS);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const fileCount = countFiles(dir);
|
|
230
|
+
const subdirs = readdirSync(dir, { withFileTypes: true }).filter(e => e.isDirectory() && !e.name.startsWith('.')).length;
|
|
231
|
+
const space = isSpace(dir);
|
|
232
|
+
|
|
233
|
+
const info = { name: basename(relPath), path: relPath, type: space ? 'space' : 'dir', fileCount, subdirs, modified: stat.mtime.toISOString() };
|
|
234
|
+
|
|
235
|
+
if (isJsonMode(flags)) {
|
|
236
|
+
output(info, flags);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
console.log(`\n${bold(relPath)}\n`);
|
|
241
|
+
console.log(` ${dim('Type:'.padEnd(15))}${space ? cyan('Space') : 'Directory'}`);
|
|
242
|
+
console.log(` ${dim('Files:'.padEnd(15))}${fileCount}`);
|
|
243
|
+
console.log(` ${dim('Subdirs:'.padEnd(15))}${subdirs}`);
|
|
244
|
+
console.log(` ${dim('Modified:'.padEnd(15))}${info.modified}`);
|
|
245
|
+
if (!space) {
|
|
246
|
+
console.log(`\n ${dim('Tip: `mindos space init "' + relPath + '"` to upgrade to a Space')}`);
|
|
247
|
+
}
|
|
248
|
+
console.log();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// ── create: new Space (dir + INSTRUCTION.md) ──────────────────────────────────
|
|
252
|
+
|
|
122
253
|
function spaceCreate(root, name, flags) {
|
|
123
254
|
if (!name) {
|
|
124
255
|
console.error(red('Usage: mindos space create <name>'));
|
|
125
|
-
process.exit(EXIT.
|
|
256
|
+
process.exit(EXIT.ARGS);
|
|
126
257
|
}
|
|
127
258
|
const dir = resolve(root, name);
|
|
128
259
|
if (existsSync(dir)) {
|
|
129
|
-
console.error(red(`
|
|
260
|
+
console.error(red(`Already exists: ${name}`));
|
|
130
261
|
process.exit(EXIT.ERROR);
|
|
131
262
|
}
|
|
132
263
|
|
|
133
264
|
mkdirSync(dir, { recursive: true });
|
|
134
|
-
writeFileSync(resolve(dir, 'INSTRUCTION.md'), `# ${name}\n\nSpace instructions go here.\n`, 'utf-8');
|
|
265
|
+
writeFileSync(resolve(dir, 'INSTRUCTION.md'), `# ${basename(name)}\n\nSpace instructions go here.\n`, 'utf-8');
|
|
266
|
+
writeFileSync(resolve(dir, 'README.md'), `# ${basename(name)}\n`, 'utf-8');
|
|
135
267
|
|
|
136
268
|
if (isJsonMode(flags)) {
|
|
137
|
-
output({ ok: true, name,
|
|
269
|
+
output({ ok: true, name, type: 'space' }, flags);
|
|
138
270
|
return;
|
|
139
271
|
}
|
|
140
|
-
console.log(`${green('✔')} Created
|
|
272
|
+
console.log(`${green('✔')} Created Space: ${cyan(name)}`);
|
|
141
273
|
}
|
|
142
274
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
275
|
+
// ── mkdir: plain directory ────────────────────────────────────────────────────
|
|
276
|
+
|
|
277
|
+
function spaceMkdir(root, relPath, flags) {
|
|
278
|
+
if (!relPath) {
|
|
279
|
+
console.error(red('Usage: mindos space mkdir <path>'));
|
|
280
|
+
process.exit(EXIT.ARGS);
|
|
147
281
|
}
|
|
148
|
-
const
|
|
149
|
-
if (
|
|
150
|
-
|
|
151
|
-
|
|
282
|
+
const full = resolve(root, relPath);
|
|
283
|
+
if (existsSync(full)) {
|
|
284
|
+
if (isJsonMode(flags)) {
|
|
285
|
+
output({ ok: true, path: relPath, created: false }, flags);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
console.log(dim(`Already exists: ${relPath}`));
|
|
289
|
+
return;
|
|
152
290
|
}
|
|
153
291
|
|
|
292
|
+
mkdirSync(full, { recursive: true });
|
|
293
|
+
|
|
294
|
+
if (isJsonMode(flags)) {
|
|
295
|
+
output({ ok: true, path: relPath, created: true }, flags);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
console.log(`${green('✔')} Created directory: ${cyan(relPath)}`);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ── rmdir: delete directory ───────────────────────────────────────────────────
|
|
302
|
+
|
|
303
|
+
function spaceRmdir(root, relPath, flags) {
|
|
304
|
+
if (!relPath) {
|
|
305
|
+
console.error(red('Usage: mindos space rmdir <path>'));
|
|
306
|
+
process.exit(EXIT.ARGS);
|
|
307
|
+
}
|
|
308
|
+
const dir = resolvePath(root, relPath);
|
|
154
309
|
const fileCount = countFiles(dir);
|
|
155
310
|
rmSync(dir, { recursive: true, force: true });
|
|
156
311
|
|
|
157
312
|
if (isJsonMode(flags)) {
|
|
158
|
-
output({ ok: true,
|
|
313
|
+
output({ ok: true, path: relPath, deletedFiles: fileCount }, flags);
|
|
159
314
|
return;
|
|
160
315
|
}
|
|
161
|
-
console.log(`${green('✔')} Deleted
|
|
316
|
+
console.log(`${green('✔')} Deleted: ${cyan(relPath)} (${fileCount} files removed)`);
|
|
162
317
|
}
|
|
163
318
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const newDir = resolve(root, newName);
|
|
171
|
-
if (!existsSync(oldDir)) {
|
|
172
|
-
console.error(red(`Space not found: ${oldName}`));
|
|
173
|
-
process.exit(EXIT.ERROR);
|
|
319
|
+
// ── rename ────────────────────────────────────────────────────────────────────
|
|
320
|
+
|
|
321
|
+
function spaceRename(root, oldPath, newPath, flags) {
|
|
322
|
+
if (!oldPath || !newPath) {
|
|
323
|
+
console.error(red('Usage: mindos space rename <old-path> <new-path>'));
|
|
324
|
+
process.exit(EXIT.ARGS);
|
|
174
325
|
}
|
|
326
|
+
const oldDir = resolvePath(root, oldPath);
|
|
327
|
+
const newDir = resolve(root, newPath);
|
|
175
328
|
if (existsSync(newDir)) {
|
|
176
|
-
console.error(red(`Target already exists: ${
|
|
329
|
+
console.error(red(`Target already exists: ${newPath}`));
|
|
177
330
|
process.exit(EXIT.ERROR);
|
|
178
331
|
}
|
|
179
332
|
|
|
333
|
+
// Ensure parent of target exists
|
|
334
|
+
const parentDir = resolve(newDir, '..');
|
|
335
|
+
if (!existsSync(parentDir)) mkdirSync(parentDir, { recursive: true });
|
|
336
|
+
|
|
180
337
|
renameSync(oldDir, newDir);
|
|
181
338
|
|
|
182
339
|
if (isJsonMode(flags)) {
|
|
183
|
-
output({ ok: true, from:
|
|
340
|
+
output({ ok: true, from: oldPath, to: newPath }, flags);
|
|
184
341
|
return;
|
|
185
342
|
}
|
|
186
|
-
console.log(`${green('✔')} Renamed
|
|
343
|
+
console.log(`${green('✔')} Renamed: ${cyan(oldPath)} → ${cyan(newPath)}`);
|
|
187
344
|
}
|
|
188
345
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
346
|
+
// ── init: upgrade directory to Space ──────────────────────────────────────────
|
|
347
|
+
|
|
348
|
+
function spaceInit(root, relPath, flags) {
|
|
349
|
+
if (!relPath) {
|
|
350
|
+
console.error(red('Usage: mindos space init <path>'));
|
|
351
|
+
process.exit(EXIT.ARGS);
|
|
193
352
|
}
|
|
194
|
-
const dir = resolve(root,
|
|
353
|
+
const dir = resolve(root, relPath);
|
|
354
|
+
|
|
355
|
+
// If doesn't exist, create it + init as Space
|
|
195
356
|
if (!existsSync(dir)) {
|
|
196
|
-
|
|
197
|
-
process.exit(EXIT.ERROR);
|
|
357
|
+
mkdirSync(dir, { recursive: true });
|
|
198
358
|
}
|
|
199
359
|
|
|
200
|
-
|
|
201
|
-
|
|
360
|
+
if (isSpace(dir)) {
|
|
361
|
+
if (isJsonMode(flags)) {
|
|
362
|
+
output({ ok: true, path: relPath, initialized: false, message: 'already a Space' }, flags);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
console.log(dim(`Already a Space: ${relPath}`));
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
202
368
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
isSpace: isSpace(dir),
|
|
208
|
-
modified: stat.mtime.toISOString(),
|
|
209
|
-
};
|
|
369
|
+
writeFileSync(resolve(dir, 'INSTRUCTION.md'), `# ${basename(relPath)}\n\nSpace instructions go here.\n`, 'utf-8');
|
|
370
|
+
if (!existsSync(resolve(dir, 'README.md'))) {
|
|
371
|
+
writeFileSync(resolve(dir, 'README.md'), `# ${basename(relPath)}\n`, 'utf-8');
|
|
372
|
+
}
|
|
210
373
|
|
|
211
374
|
if (isJsonMode(flags)) {
|
|
212
|
-
output(
|
|
375
|
+
output({ ok: true, path: relPath, initialized: true }, flags);
|
|
213
376
|
return;
|
|
214
377
|
}
|
|
215
|
-
|
|
216
|
-
console.log(`\n${bold(`Space: ${name}`)}\n`);
|
|
217
|
-
console.log(` ${dim('Files:'.padEnd(15))}${fileCount}`);
|
|
218
|
-
console.log(` ${dim('Is Space:'.padEnd(15))}${info.isSpace ? green('yes') : 'no (folder)'}`);
|
|
219
|
-
console.log(` ${dim('Modified:'.padEnd(15))}${info.modified}`);
|
|
220
|
-
console.log();
|
|
378
|
+
console.log(`${green('✔')} Initialized Space: ${cyan(relPath)}`);
|
|
221
379
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
title: Sprint Release Workflow
|
|
2
|
+
description: Weekly sprint release process with multi-agent collaboration and comprehensive QA
|
|
3
|
+
|
|
4
|
+
# Global configuration - skills available across all steps
|
|
5
|
+
skills:
|
|
6
|
+
- software-architecture
|
|
7
|
+
- code-review-quality
|
|
8
|
+
- document-release
|
|
9
|
+
|
|
10
|
+
# Global tools guidance (advisory - LLM auto-selects based on context)
|
|
11
|
+
tools:
|
|
12
|
+
- git
|
|
13
|
+
- npm
|
|
14
|
+
- github
|
|
15
|
+
|
|
16
|
+
# Workflow steps - executed sequentially
|
|
17
|
+
steps:
|
|
18
|
+
# Step 1: Run comprehensive test suite
|
|
19
|
+
- id: run_tests
|
|
20
|
+
name: Run tests
|
|
21
|
+
description: Execute full test suite and report results with coverage metrics
|
|
22
|
+
agent: cursor
|
|
23
|
+
prompt: |
|
|
24
|
+
Execute the full test suite for this project.
|
|
25
|
+
|
|
26
|
+
Provide:
|
|
27
|
+
1. Total tests run, passed, failed
|
|
28
|
+
2. Coverage report (lines/branches/functions)
|
|
29
|
+
3. Any critical failures with recommendations
|
|
30
|
+
4. Time taken
|
|
31
|
+
|
|
32
|
+
If failures exist, list the top 3 most critical with suggested fixes.
|
|
33
|
+
timeout: 120
|
|
34
|
+
|
|
35
|
+
# Step 2: Code review with dedicated AI agent
|
|
36
|
+
- id: code_review
|
|
37
|
+
name: Code review
|
|
38
|
+
description: Comprehensive code review using software architecture principles
|
|
39
|
+
agent: claude-code
|
|
40
|
+
skill: code-review-quality
|
|
41
|
+
prompt: |
|
|
42
|
+
Review the recent code changes using the code-review-quality standard.
|
|
43
|
+
|
|
44
|
+
Evaluate:
|
|
45
|
+
1. Correctness - error handling, edge cases
|
|
46
|
+
2. Security - authentication, input validation, secrets
|
|
47
|
+
3. Performance - N+1 queries, caching, complexity
|
|
48
|
+
4. Maintainability - naming, tests, documentation
|
|
49
|
+
5. Architecture - follows project patterns, no anti-patterns
|
|
50
|
+
|
|
51
|
+
Provide a rating (e.g., 8.5/10) and key recommendations.
|
|
52
|
+
timeout: 120
|
|
53
|
+
|
|
54
|
+
# Step 3: Automated security scan (no agent - use LLM with tools)
|
|
55
|
+
- id: security_check
|
|
56
|
+
name: Security scan
|
|
57
|
+
description: Run security analysis and dependency checks
|
|
58
|
+
tools:
|
|
59
|
+
- npm
|
|
60
|
+
- github
|
|
61
|
+
prompt: |
|
|
62
|
+
Perform security checks on this project:
|
|
63
|
+
|
|
64
|
+
1. Check for known vulnerabilities in npm dependencies
|
|
65
|
+
2. Review recent dependency changes
|
|
66
|
+
3. Check for hardcoded secrets or credentials
|
|
67
|
+
4. Evaluate access control and authentication mechanisms
|
|
68
|
+
5. Assess error handling for information leaks
|
|
69
|
+
|
|
70
|
+
Report severity and recommended fixes.
|
|
71
|
+
timeout: 60
|
|
72
|
+
|
|
73
|
+
# Step 4: Update documentation using document-release skill
|
|
74
|
+
- id: update_docs
|
|
75
|
+
name: Update documentation
|
|
76
|
+
description: Sync CHANGELOG, README, and API docs with shipped changes
|
|
77
|
+
skill: document-release
|
|
78
|
+
prompt: |
|
|
79
|
+
Update project documentation based on the shipped changes:
|
|
80
|
+
|
|
81
|
+
1. Update CHANGELOG.md following semantic versioning
|
|
82
|
+
2. Update README.md if features or APIs changed
|
|
83
|
+
3. Update API documentation if endpoints changed
|
|
84
|
+
4. Verify all documentation links are valid
|
|
85
|
+
5. Check code examples match current implementation
|
|
86
|
+
|
|
87
|
+
Provide a summary of all documentation updates made.
|
|
88
|
+
timeout: 60
|
|
89
|
+
|
|
90
|
+
# Step 5: Final checklist before release
|
|
91
|
+
- id: pre_release_check
|
|
92
|
+
name: Pre-release verification
|
|
93
|
+
description: Final comprehensive verification before shipping
|
|
94
|
+
agent: mindos
|
|
95
|
+
prompt: |
|
|
96
|
+
Perform final pre-release verification:
|
|
97
|
+
|
|
98
|
+
Checklist:
|
|
99
|
+
☐ All tests passing
|
|
100
|
+
☐ Code review completed and issues resolved
|
|
101
|
+
☐ Security scan passed or risks accepted
|
|
102
|
+
☐ Documentation updated and links valid
|
|
103
|
+
☐ Version bumped correctly (semver)
|
|
104
|
+
☐ Git tags and commits clean
|
|
105
|
+
☐ No uncommitted changes
|
|
106
|
+
☐ Changelog entry present
|
|
107
|
+
☐ Dependencies updated and locked
|
|
108
|
+
☐ Performance benchmarks acceptable
|
|
109
|
+
|
|
110
|
+
Confirm release readiness or list any blockers.
|
|
111
|
+
timeout: 60
|
|
112
|
+
|
|
113
|
+
# Step 6: Create release tag and prepare release notes
|
|
114
|
+
- id: create_release
|
|
115
|
+
name: Create release
|
|
116
|
+
description: Tag release and prepare release notes for publishing
|
|
117
|
+
tools:
|
|
118
|
+
- git
|
|
119
|
+
- npm
|
|
120
|
+
prompt: |
|
|
121
|
+
Prepare the project for release:
|
|
122
|
+
|
|
123
|
+
1. Confirm version in package.json matches intended release
|
|
124
|
+
2. Create git tag for this version (vX.Y.Z)
|
|
125
|
+
3. Generate release notes from CHANGELOG.md
|
|
126
|
+
4. Prepare npm release command (do not execute yet)
|
|
127
|
+
5. List all deliverables included in this release
|
|
128
|
+
|
|
129
|
+
Provide step-by-step commands for final publishing.
|
|
130
|
+
timeout: 60
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
title: 周迭代检查工作流
|
|
2
|
+
description: 每周进行代码审查、测试运行和文档更新的标准工作流
|
|
3
|
+
|
|
4
|
+
# 全局配置 - 此工作流可用的技能
|
|
5
|
+
skills:
|
|
6
|
+
- software-architecture
|
|
7
|
+
- code-review-quality
|
|
8
|
+
|
|
9
|
+
# 工作流步骤 - 按顺序执行
|
|
10
|
+
steps:
|
|
11
|
+
# 第 1 步:运行测试套件
|
|
12
|
+
- id: run_tests
|
|
13
|
+
name: 运行测试
|
|
14
|
+
description: 执行完整测试套件并报告覆盖率
|
|
15
|
+
agent: cursor
|
|
16
|
+
prompt: |
|
|
17
|
+
执行此项目的完整测试套件。
|
|
18
|
+
|
|
19
|
+
提供以下信息:
|
|
20
|
+
1. 运行的总测试数、通过数、失败数
|
|
21
|
+
2. 覆盖率报告(行/分支/函数)
|
|
22
|
+
3. 任何严重失败及修复建议
|
|
23
|
+
4. 耗时
|
|
24
|
+
|
|
25
|
+
如果有失败,列出前 3 个最严重的失败及建议的修复方案。
|
|
26
|
+
timeout: 120
|
|
27
|
+
|
|
28
|
+
# 第 2 步:代码审查
|
|
29
|
+
- id: code_review
|
|
30
|
+
name: 代码审查
|
|
31
|
+
description: 使用标准进行代码审查
|
|
32
|
+
agent: claude-code
|
|
33
|
+
skill: code-review-quality
|
|
34
|
+
prompt: |
|
|
35
|
+
使用代码审查标准对最近的代码变更进行审查。
|
|
36
|
+
|
|
37
|
+
评估以下方面:
|
|
38
|
+
1. 正确性 - 错误处理、边界情况
|
|
39
|
+
2. 安全性 - 认证、输入验证、密钥管理
|
|
40
|
+
3. 性能 - 查询优化、缓存策略、复杂度
|
|
41
|
+
4. 可维护性 - 命名规范、测试覆盖、文档完整性
|
|
42
|
+
5. 架构 - 是否遵循项目模式,有无反模式
|
|
43
|
+
|
|
44
|
+
给出评分(如 8.5/10)和主要建议。
|
|
45
|
+
timeout: 120
|
|
46
|
+
|
|
47
|
+
# 第 3 步:更新文档
|
|
48
|
+
- id: update_docs
|
|
49
|
+
name: 更新文档
|
|
50
|
+
description: 同步 CHANGELOG 和 README
|
|
51
|
+
skill: document-release
|
|
52
|
+
prompt: |
|
|
53
|
+
根据本次发布的变更更新项目文档:
|
|
54
|
+
|
|
55
|
+
1. 更新 CHANGELOG.md,遵循语义化版本规范
|
|
56
|
+
2. 如果功能或 API 变更,更新 README.md
|
|
57
|
+
3. 如果端点变更,更新 API 文档
|
|
58
|
+
4. 验证所有文档链接有效
|
|
59
|
+
5. 检查代码示例是否匹配当前实现
|
|
60
|
+
|
|
61
|
+
提供所有文档变更的摘要。
|
|
62
|
+
timeout: 60
|
|
63
|
+
|
|
64
|
+
# 第 4 步:发布前最终检查
|
|
65
|
+
- id: final_check
|
|
66
|
+
name: 发布前验证
|
|
67
|
+
description: 最终确认一切就绪
|
|
68
|
+
agent: mindos
|
|
69
|
+
prompt: |
|
|
70
|
+
进行最终的发布前验证检查:
|
|
71
|
+
|
|
72
|
+
清单:
|
|
73
|
+
☐ 所有测试通过
|
|
74
|
+
☐ 代码审查完成并问题已解决
|
|
75
|
+
☐ 文档已更新并链接有效
|
|
76
|
+
☐ 版本号正确升级(语义化版本)
|
|
77
|
+
☐ Git 标签和提交干净
|
|
78
|
+
☐ 无未提交的更改
|
|
79
|
+
☐ CHANGELOG 条目存在
|
|
80
|
+
☐ 依赖项已更新并锁定
|
|
81
|
+
☐ 性能基准可接受
|
|
82
|
+
|
|
83
|
+
确认发布就绪或列出任何阻碍因素。
|
|
84
|
+
timeout: 60
|