@geminilight/mindos 0.6.28 → 0.6.29
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/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/detect/route.ts +91 -0
- package/app/app/api/acp/registry/route.ts +31 -0
- package/app/app/api/acp/session/route.ts +55 -0
- package/app/app/layout.tsx +2 -0
- package/app/components/DirView.tsx +64 -2
- package/app/components/FileTree.tsx +19 -0
- package/app/components/GuideCard.tsx +7 -17
- package/app/components/MarkdownView.tsx +2 -0
- package/app/components/SearchModal.tsx +234 -80
- package/app/components/agents/AgentDetailContent.tsx +3 -5
- package/app/components/agents/AgentsContentPage.tsx +21 -6
- package/app/components/agents/AgentsPanelA2aTab.tsx +445 -0
- package/app/components/agents/SkillDetailPopover.tsx +4 -9
- package/app/components/agents/agents-content-model.ts +2 -2
- package/app/components/help/HelpContent.tsx +9 -9
- package/app/components/panels/AgentsPanel.tsx +1 -0
- package/app/components/panels/AgentsPanelAgentDetail.tsx +5 -8
- package/app/components/panels/AgentsPanelHubNav.tsx +8 -1
- package/app/components/panels/EchoPanel.tsx +5 -1
- package/app/components/panels/EchoSidebarStats.tsx +136 -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/useAcpDetection.ts +65 -0
- package/app/hooks/useAcpRegistry.ts +51 -0
- package/app/hooks/useDelegationHistory.ts +49 -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 +93 -0
- package/app/lib/acp/bridge.ts +138 -0
- package/app/lib/acp/index.ts +24 -0
- package/app/lib/acp/registry.ts +135 -0
- package/app/lib/acp/session.ts +264 -0
- package/app/lib/acp/subprocess.ts +209 -0
- package/app/lib/acp/types.ts +136 -0
- 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 +425 -0
- package/app/lib/i18n/modules/navigation.ts +151 -0
- package/app/lib/i18n/modules/onboarding.ts +523 -0
- package/app/lib/i18n/modules/panels.ts +1052 -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/toast.ts +79 -0
- 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/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