mnotes-cli 1.6.0 → 1.7.1
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/dist/commands/connect/index.js +15 -23
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +5 -0
- package/dist/commands/workspace.js +146 -34
- package/dist/config.js +29 -1
- package/package.json +1 -1
|
@@ -40,6 +40,7 @@ const fs = __importStar(require("fs"));
|
|
|
40
40
|
const path = __importStar(require("path"));
|
|
41
41
|
const config_utils_1 = require("./config-utils");
|
|
42
42
|
const workspace_prompt_1 = require("./workspace-prompt");
|
|
43
|
+
const config_1 = require("../../config");
|
|
43
44
|
const claude_code_1 = require("../../templates/claude-code");
|
|
44
45
|
const codex_1 = require("../../templates/codex");
|
|
45
46
|
const openclaw_1 = require("../../templates/openclaw");
|
|
@@ -91,11 +92,11 @@ function printConnectionStatus() {
|
|
|
91
92
|
* prompts interactively after validating the connection.
|
|
92
93
|
*/
|
|
93
94
|
async function resolveWorkspace(opts) {
|
|
94
|
-
//
|
|
95
|
-
const
|
|
96
|
-
if (
|
|
97
|
-
return
|
|
98
|
-
//
|
|
95
|
+
// Check flag, env, dir map, global config
|
|
96
|
+
const fromConfig = (0, config_1.resolveConfig)({ workspaceId: opts.workspace });
|
|
97
|
+
if (fromConfig.workspaceId)
|
|
98
|
+
return fromConfig.workspaceId;
|
|
99
|
+
// Nothing stored — interactive selection/creation
|
|
99
100
|
const resolved = await (0, workspace_prompt_1.resolveWorkspaceInteractively)(opts.url, opts.apiKey);
|
|
100
101
|
return resolved.id;
|
|
101
102
|
}
|
|
@@ -110,12 +111,9 @@ function normalizeBaseUrl(raw) {
|
|
|
110
111
|
return raw.replace(/\/+$/, "").replace(/\/api\/mcp$/i, "");
|
|
111
112
|
}
|
|
112
113
|
async function handleClaudeCode(opts) {
|
|
113
|
-
const
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
process.stderr.write("Error: API key required. Use --api-key or set MNOTES_API_KEY\n");
|
|
117
|
-
process.exit(1);
|
|
118
|
-
}
|
|
114
|
+
const config = (0, config_1.resolveConfig)(opts);
|
|
115
|
+
const url = normalizeBaseUrl(config.baseUrl);
|
|
116
|
+
const apiKey = config.apiKey;
|
|
119
117
|
const validation = await (0, config_utils_1.validateConnection)(url, apiKey);
|
|
120
118
|
if (!validation.ok) {
|
|
121
119
|
process.stderr.write(`Error: Cannot connect to ${url}: ${validation.error}\n`);
|
|
@@ -179,12 +177,9 @@ function printScaffoldResults(results) {
|
|
|
179
177
|
* Handles the `codex` integration target.
|
|
180
178
|
*/
|
|
181
179
|
async function handleCodex(opts) {
|
|
182
|
-
const
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
process.stderr.write("Error: API key required. Use --api-key or set MNOTES_API_KEY\n");
|
|
186
|
-
process.exit(1);
|
|
187
|
-
}
|
|
180
|
+
const config = (0, config_1.resolveConfig)(opts);
|
|
181
|
+
const url = normalizeBaseUrl(config.baseUrl);
|
|
182
|
+
const apiKey = config.apiKey;
|
|
188
183
|
const validation = await (0, config_utils_1.validateConnection)(url, apiKey);
|
|
189
184
|
if (!validation.ok) {
|
|
190
185
|
process.stderr.write(`Error: Cannot connect to ${url}: ${validation.error}\n`);
|
|
@@ -216,13 +211,10 @@ async function handleCodex(opts) {
|
|
|
216
211
|
* Handles the `openclaw` integration target.
|
|
217
212
|
*/
|
|
218
213
|
async function handleOpenClaw(opts) {
|
|
219
|
-
const
|
|
220
|
-
const
|
|
214
|
+
const config = (0, config_1.resolveConfig)(opts);
|
|
215
|
+
const url = normalizeBaseUrl(config.baseUrl);
|
|
216
|
+
const apiKey = config.apiKey;
|
|
221
217
|
const configPath = opts.configPath || path.join(process.env.HOME || "~", ".openclaw", "mcp.json");
|
|
222
|
-
if (!apiKey) {
|
|
223
|
-
process.stderr.write("Error: API key required. Use --api-key or set MNOTES_API_KEY\n");
|
|
224
|
-
process.exit(1);
|
|
225
|
-
}
|
|
226
218
|
const validation = await (0, config_utils_1.validateConnection)(url, apiKey);
|
|
227
219
|
if (!validation.ok) {
|
|
228
220
|
process.stderr.write(`Error: Cannot connect to ${url}: ${validation.error}\n`);
|
package/dist/commands/login.d.ts
CHANGED
package/dist/commands/login.js
CHANGED
|
@@ -62,10 +62,15 @@ function readConfig() {
|
|
|
62
62
|
const raw = fs.readFileSync(configPath(), "utf-8");
|
|
63
63
|
const parsed = JSON.parse(raw);
|
|
64
64
|
if (typeof parsed.apiKey === "string" && typeof parsed.serverUrl === "string") {
|
|
65
|
+
let workspaces;
|
|
66
|
+
if (typeof parsed.workspaces === "object" && parsed.workspaces !== null && !Array.isArray(parsed.workspaces)) {
|
|
67
|
+
workspaces = parsed.workspaces;
|
|
68
|
+
}
|
|
65
69
|
return {
|
|
66
70
|
apiKey: parsed.apiKey,
|
|
67
71
|
serverUrl: parsed.serverUrl,
|
|
68
72
|
workspaceId: typeof parsed.workspaceId === "string" ? parsed.workspaceId : undefined,
|
|
73
|
+
workspaces,
|
|
69
74
|
};
|
|
70
75
|
}
|
|
71
76
|
return null;
|
|
@@ -45,6 +45,26 @@ function ask(rl, question) {
|
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
|
+
/** Save a directory → workspace mapping in config. */
|
|
49
|
+
function saveDirectoryMapping(dir, workspaceId) {
|
|
50
|
+
const stored = (0, login_1.readConfig)();
|
|
51
|
+
if (!stored) {
|
|
52
|
+
process.stderr.write("Error: not logged in. Run `mnotes login` first.\n");
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
const workspaces = stored.workspaces ?? {};
|
|
56
|
+
workspaces[dir] = workspaceId;
|
|
57
|
+
(0, login_1.writeConfig)({ ...stored, workspaces });
|
|
58
|
+
}
|
|
59
|
+
/** Remove a directory → workspace mapping from config. */
|
|
60
|
+
function removeDirectoryMapping(dir) {
|
|
61
|
+
const stored = (0, login_1.readConfig)();
|
|
62
|
+
if (!stored?.workspaces?.[dir])
|
|
63
|
+
return false;
|
|
64
|
+
delete stored.workspaces[dir];
|
|
65
|
+
(0, login_1.writeConfig)(stored);
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
48
68
|
function registerWorkspaceCommand(program) {
|
|
49
69
|
const ws = program
|
|
50
70
|
.command("workspace")
|
|
@@ -62,20 +82,25 @@ function registerWorkspaceCommand(program) {
|
|
|
62
82
|
return;
|
|
63
83
|
}
|
|
64
84
|
const stored = (0, login_1.readConfig)();
|
|
65
|
-
const
|
|
85
|
+
const cwd = process.cwd();
|
|
86
|
+
const dirMapped = stored?.workspaces?.[cwd];
|
|
87
|
+
const globalDefault = stored?.workspaceId;
|
|
66
88
|
for (const w of workspaces) {
|
|
67
89
|
const markers = [];
|
|
68
90
|
if (w.isDefault)
|
|
69
91
|
markers.push("default");
|
|
70
|
-
if (w.id ===
|
|
71
|
-
markers.push("
|
|
92
|
+
if (w.id === dirMapped)
|
|
93
|
+
markers.push("linked");
|
|
94
|
+
else if (w.id === globalDefault)
|
|
95
|
+
markers.push("global");
|
|
72
96
|
const suffix = markers.length > 0 ? ` (${markers.join(", ")})` : "";
|
|
73
97
|
console.log(` ${w.name} [${w.slug}]${suffix}`);
|
|
74
98
|
}
|
|
75
99
|
});
|
|
76
100
|
ws.command("select")
|
|
77
|
-
.description("Select
|
|
78
|
-
.
|
|
101
|
+
.description("Select workspace for current directory (saved to config)")
|
|
102
|
+
.option("--global", "Set as global default instead of per-directory")
|
|
103
|
+
.action(async (opts) => {
|
|
79
104
|
const globalOpts = program.opts();
|
|
80
105
|
const config = (0, config_1.resolveConfig)(globalOpts);
|
|
81
106
|
const client = (0, client_1.createClient)(config.baseUrl, config.apiKey);
|
|
@@ -86,7 +111,8 @@ function registerWorkspaceCommand(program) {
|
|
|
86
111
|
return;
|
|
87
112
|
}
|
|
88
113
|
const stored = (0, login_1.readConfig)();
|
|
89
|
-
const
|
|
114
|
+
const cwd = process.cwd();
|
|
115
|
+
const currentId = stored?.workspaces?.[cwd] || stored?.workspaceId;
|
|
90
116
|
const rl = readline.createInterface({
|
|
91
117
|
input: process.stdin,
|
|
92
118
|
output: process.stderr,
|
|
@@ -95,7 +121,7 @@ function registerWorkspaceCommand(program) {
|
|
|
95
121
|
process.stderr.write("\nWorkspaces:\n");
|
|
96
122
|
for (let i = 0; i < workspaces.length; i++) {
|
|
97
123
|
const w = workspaces[i];
|
|
98
|
-
const marker = w.id ===
|
|
124
|
+
const marker = w.id === currentId ? " *" : "";
|
|
99
125
|
process.stderr.write(` ${i + 1}. ${w.name} [${w.slug}]${marker}\n`);
|
|
100
126
|
}
|
|
101
127
|
const answer = await ask(rl, `\nSelect workspace [1-${workspaces.length}]: `);
|
|
@@ -105,52 +131,138 @@ function registerWorkspaceCommand(program) {
|
|
|
105
131
|
process.exit(1);
|
|
106
132
|
}
|
|
107
133
|
const selected = workspaces[choice - 1];
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
134
|
+
if (opts.global) {
|
|
135
|
+
const existing = stored ?? { apiKey: config.apiKey, serverUrl: config.baseUrl };
|
|
136
|
+
(0, login_1.writeConfig)({ ...existing, workspaceId: selected.id });
|
|
137
|
+
console.log(`Global default workspace: ${selected.name} [${selected.slug}]`);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
saveDirectoryMapping(cwd, selected.id);
|
|
141
|
+
console.log(`Linked ${cwd} → ${selected.name} [${selected.slug}]`);
|
|
142
|
+
}
|
|
111
143
|
}
|
|
112
144
|
finally {
|
|
113
145
|
rl.close();
|
|
114
146
|
}
|
|
115
147
|
});
|
|
116
|
-
ws.command("
|
|
148
|
+
ws.command("link")
|
|
149
|
+
.description("Link current directory to a workspace")
|
|
150
|
+
.argument("[workspace-id]", "Workspace ID or slug (interactive if omitted)")
|
|
151
|
+
.action(async (workspaceIdOrSlug) => {
|
|
152
|
+
const globalOpts = program.opts();
|
|
153
|
+
const config = (0, config_1.resolveConfig)(globalOpts);
|
|
154
|
+
const client = (0, client_1.createClient)(config.baseUrl, config.apiKey);
|
|
155
|
+
const res = await client.listWorkspaces();
|
|
156
|
+
const workspaces = res.data;
|
|
157
|
+
if (workspaces.length === 0) {
|
|
158
|
+
console.log("No workspaces found. Create one with: mnotes workspace create <name>");
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const cwd = process.cwd();
|
|
162
|
+
let selected;
|
|
163
|
+
if (workspaceIdOrSlug) {
|
|
164
|
+
selected = workspaces.find((w) => w.id === workspaceIdOrSlug || w.slug === workspaceIdOrSlug);
|
|
165
|
+
if (!selected) {
|
|
166
|
+
process.stderr.write(`Error: workspace "${workspaceIdOrSlug}" not found.\n`);
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
const rl = readline.createInterface({
|
|
172
|
+
input: process.stdin,
|
|
173
|
+
output: process.stderr,
|
|
174
|
+
});
|
|
175
|
+
try {
|
|
176
|
+
process.stderr.write("\nWorkspaces:\n");
|
|
177
|
+
for (let i = 0; i < workspaces.length; i++) {
|
|
178
|
+
const w = workspaces[i];
|
|
179
|
+
process.stderr.write(` ${i + 1}. ${w.name} [${w.slug}]\n`);
|
|
180
|
+
}
|
|
181
|
+
const answer = await ask(rl, `\nLink to workspace [1-${workspaces.length}]: `);
|
|
182
|
+
const choice = parseInt(answer, 10);
|
|
183
|
+
if (choice < 1 || choice > workspaces.length || isNaN(choice)) {
|
|
184
|
+
process.stderr.write("Invalid selection.\n");
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
selected = workspaces[choice - 1];
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
rl.close();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
saveDirectoryMapping(cwd, selected.id);
|
|
194
|
+
console.log(`Linked ${cwd} → ${selected.name} [${selected.slug}]`);
|
|
195
|
+
});
|
|
196
|
+
ws.command("unlink")
|
|
197
|
+
.description("Remove workspace mapping for current directory")
|
|
198
|
+
.action(async () => {
|
|
199
|
+
const cwd = process.cwd();
|
|
200
|
+
const removed = removeDirectoryMapping(cwd);
|
|
201
|
+
if (removed) {
|
|
202
|
+
console.log(`Unlinked ${cwd}`);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
console.log(`No workspace linked to ${cwd}`);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
ws.command("create")
|
|
117
209
|
.description("Create a new workspace")
|
|
210
|
+
.argument("<name>", "Workspace name")
|
|
118
211
|
.action(async (name) => {
|
|
119
212
|
const globalOpts = program.opts();
|
|
120
213
|
const config = (0, config_1.resolveConfig)(globalOpts);
|
|
121
214
|
const client = (0, client_1.createClient)(config.baseUrl, config.apiKey);
|
|
122
215
|
const res = await client.createWorkspace(name);
|
|
123
216
|
console.log(`Created workspace: ${res.data.name} [${res.data.slug}]`);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
console.log("Auto-selected as default workspace.");
|
|
129
|
-
}
|
|
217
|
+
// Auto-link to current directory
|
|
218
|
+
const cwd = process.cwd();
|
|
219
|
+
saveDirectoryMapping(cwd, res.data.id);
|
|
220
|
+
console.log(`Linked ${cwd} → ${res.data.name}`);
|
|
130
221
|
});
|
|
131
222
|
ws.command("current")
|
|
132
|
-
.description("Show
|
|
223
|
+
.description("Show workspace for current directory")
|
|
133
224
|
.action(async () => {
|
|
134
225
|
const stored = (0, login_1.readConfig)();
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
226
|
+
const cwd = process.cwd();
|
|
227
|
+
// Check directory mapping first
|
|
228
|
+
const dirMapped = stored?.workspaces?.[cwd];
|
|
229
|
+
const effectiveId = dirMapped || stored?.workspaceId;
|
|
230
|
+
const source = dirMapped ? "linked" : stored?.workspaceId ? "global" : null;
|
|
231
|
+
if (!effectiveId) {
|
|
232
|
+
console.log(`No workspace for ${cwd}`);
|
|
233
|
+
console.log("Run: mnotes workspace select");
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const config = (0, config_1.resolveConfig)(program.opts());
|
|
237
|
+
const client = (0, client_1.createClient)(config.baseUrl, config.apiKey);
|
|
238
|
+
try {
|
|
239
|
+
const res = await client.listWorkspaces();
|
|
240
|
+
const current = res.data.find((w) => w.id === effectiveId);
|
|
241
|
+
if (current) {
|
|
242
|
+
console.log(`${current.name} [${current.slug}] (${source})`);
|
|
147
243
|
}
|
|
148
|
-
|
|
149
|
-
console.log(
|
|
244
|
+
else {
|
|
245
|
+
console.log(`${effectiveId} (${source}, not found on server)`);
|
|
150
246
|
}
|
|
151
247
|
}
|
|
152
|
-
|
|
153
|
-
console.log(
|
|
248
|
+
catch {
|
|
249
|
+
console.log(`${effectiveId} (${source})`);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
ws.command("mappings")
|
|
253
|
+
.description("Show all directory → workspace mappings")
|
|
254
|
+
.action(async () => {
|
|
255
|
+
const stored = (0, login_1.readConfig)();
|
|
256
|
+
const workspaces = stored?.workspaces;
|
|
257
|
+
if (!workspaces || Object.keys(workspaces).length === 0) {
|
|
258
|
+
console.log("No directory mappings. Use: mnotes workspace link");
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
for (const [dir, wsId] of Object.entries(workspaces)) {
|
|
262
|
+
console.log(` ${dir} → ${wsId}`);
|
|
263
|
+
}
|
|
264
|
+
if (stored?.workspaceId) {
|
|
265
|
+
console.log(`\n Global default: ${stored.workspaceId}`);
|
|
154
266
|
}
|
|
155
267
|
});
|
|
156
268
|
}
|
package/dist/config.js
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.resolveConfig = resolveConfig;
|
|
4
4
|
const login_1 = require("./commands/login");
|
|
5
|
+
/**
|
|
6
|
+
* Resolve workspace ID from (in priority order):
|
|
7
|
+
* 1. Explicit flag/option
|
|
8
|
+
* 2. MNOTES_WORKSPACE_ID env var
|
|
9
|
+
* 3. Per-directory mapping in config (cwd → workspaceId)
|
|
10
|
+
* 4. Global default workspaceId in config
|
|
11
|
+
*/
|
|
12
|
+
function resolveWorkspaceId(explicit, stored) {
|
|
13
|
+
if (explicit)
|
|
14
|
+
return explicit;
|
|
15
|
+
if (process.env.MNOTES_WORKSPACE_ID)
|
|
16
|
+
return process.env.MNOTES_WORKSPACE_ID;
|
|
17
|
+
// Check per-directory mapping
|
|
18
|
+
if (stored?.workspaces) {
|
|
19
|
+
const cwd = process.cwd();
|
|
20
|
+
// Exact match first, then walk up parent directories
|
|
21
|
+
let dir = cwd;
|
|
22
|
+
while (true) {
|
|
23
|
+
if (stored.workspaces[dir])
|
|
24
|
+
return stored.workspaces[dir];
|
|
25
|
+
const parent = require("path").dirname(dir);
|
|
26
|
+
if (parent === dir)
|
|
27
|
+
break; // reached root
|
|
28
|
+
dir = parent;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return stored?.workspaceId;
|
|
32
|
+
}
|
|
5
33
|
function resolveConfig(opts) {
|
|
6
34
|
const stored = (0, login_1.readConfig)();
|
|
7
35
|
const apiKey = opts.apiKey || process.env.MNOTES_API_KEY || stored?.apiKey;
|
|
@@ -10,6 +38,6 @@ function resolveConfig(opts) {
|
|
|
10
38
|
process.exit(1);
|
|
11
39
|
}
|
|
12
40
|
const baseUrl = opts.url || process.env.MNOTES_URL || stored?.serverUrl || "https://mnotes.framework.by";
|
|
13
|
-
const workspaceId = opts.workspaceId
|
|
41
|
+
const workspaceId = resolveWorkspaceId(opts.workspaceId, stored ?? undefined);
|
|
14
42
|
return { apiKey, baseUrl, workspaceId };
|
|
15
43
|
}
|