@waniwani/cli 0.0.34 → 0.0.35

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/index.js CHANGED
@@ -14,33 +14,31 @@ import { Command } from "commander";
14
14
  // src/lib/config.ts
15
15
  import { existsSync } from "fs";
16
16
  import { mkdir, readFile, writeFile } from "fs/promises";
17
- import { homedir } from "os";
18
17
  import { join } from "path";
19
18
  import { z } from "zod";
20
19
  var LOCAL_CONFIG_DIR = ".waniwani";
21
20
  var CONFIG_FILE_NAME = "settings.json";
22
21
  var LOCAL_DIR = join(process.cwd(), LOCAL_CONFIG_DIR);
23
22
  var LOCAL_FILE = join(LOCAL_DIR, CONFIG_FILE_NAME);
24
- var GLOBAL_DIR = join(homedir(), LOCAL_CONFIG_DIR);
25
- var GLOBAL_FILE = join(GLOBAL_DIR, CONFIG_FILE_NAME);
26
23
  var DEFAULT_API_URL = "https://app.waniwani.ai";
27
24
  var ConfigSchema = z.object({
28
- mcp: z.object({
29
- id: z.string().nullable().default(null),
30
- name: z.string().nullable().default(null)
31
- }),
32
- apiUrl: z.string().default(DEFAULT_API_URL)
25
+ // Settings
26
+ sessionId: z.string().nullable().default(null),
27
+ mcpId: z.string().nullable().default(null),
28
+ apiUrl: z.string().default(DEFAULT_API_URL),
29
+ // Auth (merged from auth.json)
30
+ accessToken: z.string().nullable().default(null),
31
+ refreshToken: z.string().nullable().default(null),
32
+ expiresAt: z.string().nullable().default(null),
33
+ clientId: z.string().nullable().default(null)
33
34
  });
34
35
  var Config = class {
35
36
  dir;
36
37
  file;
37
38
  cache = null;
38
- scope;
39
- constructor(forceGlobal = false) {
40
- const useLocal = !forceGlobal && existsSync(LOCAL_DIR);
41
- this.dir = useLocal ? LOCAL_DIR : GLOBAL_DIR;
42
- this.file = useLocal ? LOCAL_FILE : GLOBAL_FILE;
43
- this.scope = useLocal ? "local" : "global";
39
+ constructor() {
40
+ this.dir = LOCAL_DIR;
41
+ this.file = LOCAL_FILE;
44
42
  }
45
43
  async load() {
46
44
  if (!this.cache) {
@@ -59,12 +57,34 @@ var Config = class {
59
57
  await mkdir(this.dir, { recursive: true });
60
58
  await writeFile(this.file, JSON.stringify(data, null, " "));
61
59
  }
60
+ /**
61
+ * Ensure the .waniwani directory exists in cwd.
62
+ * Used by login to create config before saving tokens.
63
+ */
64
+ async ensureConfigDir() {
65
+ await mkdir(this.dir, { recursive: true });
66
+ }
67
+ /**
68
+ * Check if a .waniwani config directory exists in cwd.
69
+ */
70
+ hasConfig() {
71
+ return existsSync(this.dir);
72
+ }
73
+ // --- Settings methods ---
62
74
  async getMcpId() {
63
- return (await this.load()).mcp.id;
75
+ return (await this.load()).mcpId;
64
76
  }
65
77
  async setMcpId(id) {
66
78
  const data = await this.load();
67
- data.mcp.id = id;
79
+ data.mcpId = id;
80
+ await this.save(data);
81
+ }
82
+ async getSessionId() {
83
+ return (await this.load()).sessionId;
84
+ }
85
+ async setSessionId(id) {
86
+ const data = await this.load();
87
+ data.sessionId = id;
68
88
  await this.save(data);
69
89
  }
70
90
  async getApiUrl() {
@@ -74,9 +94,42 @@ var Config = class {
74
94
  async clear() {
75
95
  await this.save(ConfigSchema.parse({}));
76
96
  }
97
+ // --- Auth methods ---
98
+ async getAccessToken() {
99
+ return (await this.load()).accessToken;
100
+ }
101
+ async getRefreshToken() {
102
+ return (await this.load()).refreshToken;
103
+ }
104
+ async getClientId() {
105
+ return (await this.load()).clientId;
106
+ }
107
+ async setTokens(accessToken, refreshToken, expiresIn, clientId) {
108
+ const expiresAt = new Date(Date.now() + expiresIn * 1e3).toISOString();
109
+ const data = await this.load();
110
+ data.accessToken = accessToken;
111
+ data.refreshToken = refreshToken;
112
+ data.expiresAt = expiresAt;
113
+ if (clientId) {
114
+ data.clientId = clientId;
115
+ }
116
+ await this.save(data);
117
+ }
118
+ async clearAuth() {
119
+ const data = await this.load();
120
+ data.accessToken = null;
121
+ data.refreshToken = null;
122
+ data.expiresAt = null;
123
+ data.clientId = null;
124
+ await this.save(data);
125
+ }
126
+ async isTokenExpired() {
127
+ const data = await this.load();
128
+ if (!data.expiresAt) return true;
129
+ return new Date(data.expiresAt).getTime() - 5 * 60 * 1e3 < Date.now();
130
+ }
77
131
  };
78
132
  var config = new Config();
79
- var globalConfig = new Config(true);
80
133
  async function initConfigAt(dir, overrides = {}) {
81
134
  const configDir = join(dir, LOCAL_CONFIG_DIR);
82
135
  const configPath = join(configDir, CONFIG_FILE_NAME);
@@ -241,82 +294,29 @@ import { Command as Command3 } from "commander";
241
294
  import ora from "ora";
242
295
 
243
296
  // src/lib/auth.ts
244
- import { access, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
245
- import { homedir as homedir2 } from "os";
246
- import { join as join3 } from "path";
247
- import { z as z2 } from "zod";
248
- var CONFIG_DIR = join3(homedir2(), ".waniwani");
249
- var AUTH_FILE = join3(CONFIG_DIR, "auth.json");
250
- var AuthStoreSchema = z2.object({
251
- accessToken: z2.string().nullable().default(null),
252
- refreshToken: z2.string().nullable().default(null),
253
- expiresAt: z2.string().nullable().default(null),
254
- clientId: z2.string().nullable().default(null)
255
- });
256
- async function ensureConfigDir() {
257
- await mkdir2(CONFIG_DIR, { recursive: true });
258
- }
259
- async function readAuthStore() {
260
- await ensureConfigDir();
261
- try {
262
- await access(AUTH_FILE);
263
- const content = await readFile2(AUTH_FILE, "utf-8");
264
- return AuthStoreSchema.parse(JSON.parse(content));
265
- } catch {
266
- return AuthStoreSchema.parse({});
267
- }
268
- }
269
- async function writeAuthStore(store) {
270
- await ensureConfigDir();
271
- await writeFile2(AUTH_FILE, JSON.stringify(store, null, 2), "utf-8");
272
- }
273
297
  var AuthManager = class {
274
- storeCache = null;
275
- async getStore() {
276
- if (!this.storeCache) {
277
- this.storeCache = await readAuthStore();
278
- }
279
- return this.storeCache;
280
- }
281
- async saveStore(store) {
282
- this.storeCache = store;
283
- await writeAuthStore(store);
284
- }
285
298
  async isLoggedIn() {
286
- const store = await this.getStore();
287
- return !!store.accessToken;
299
+ const token = await config.getAccessToken();
300
+ return !!token;
288
301
  }
289
302
  async getAccessToken() {
290
- const store = await this.getStore();
291
- return store.accessToken;
303
+ return config.getAccessToken();
292
304
  }
293
305
  async getRefreshToken() {
294
- const store = await this.getStore();
295
- return store.refreshToken;
306
+ return config.getRefreshToken();
296
307
  }
297
308
  async setTokens(accessToken, refreshToken, expiresIn, clientId) {
298
- const expiresAt = new Date(Date.now() + expiresIn * 1e3).toISOString();
299
- const store = await this.getStore();
300
- store.accessToken = accessToken;
301
- store.refreshToken = refreshToken;
302
- store.expiresAt = expiresAt;
303
- if (clientId) {
304
- store.clientId = clientId;
305
- }
306
- await this.saveStore(store);
309
+ return config.setTokens(accessToken, refreshToken, expiresIn, clientId);
307
310
  }
308
311
  async clear() {
309
- const emptyStore = AuthStoreSchema.parse({});
310
- await this.saveStore(emptyStore);
312
+ return config.clearAuth();
311
313
  }
312
314
  async isTokenExpired() {
313
- const store = await this.getStore();
314
- if (!store.expiresAt) return true;
315
- return new Date(store.expiresAt).getTime() - 5 * 60 * 1e3 < Date.now();
315
+ return config.isTokenExpired();
316
316
  }
317
317
  async tryRefreshToken() {
318
- const store = await this.getStore();
319
- const { refreshToken, clientId } = store;
318
+ const refreshToken = await config.getRefreshToken();
319
+ const clientId = await config.getClientId();
320
320
  if (!refreshToken || !clientId) return false;
321
321
  try {
322
322
  const apiUrl = await config.getApiUrl();
@@ -468,7 +468,10 @@ async function waitForCallback(expectedState, timeoutMs = 3e5) {
468
468
  text-align: center;
469
469
  }
470
470
  .logo {
471
- height: 40px;
471
+ font-size: 1.75rem;
472
+ font-weight: 700;
473
+ color: #1e293b;
474
+ letter-spacing: -0.025em;
472
475
  }
473
476
  .icon-circle {
474
477
  width: 80px;
@@ -501,9 +504,7 @@ async function waitForCallback(expectedState, timeoutMs = 3e5) {
501
504
  <div class="blob blob-2"></div>
502
505
  <div class="blob blob-3"></div>
503
506
  <div class="container">
504
- <svg class="logo" viewBox="0 0 248 40" fill="none" xmlns="http://www.w3.org/2000/svg">
505
- <text x="0" y="32" font-family="system-ui" font-size="28" font-weight="bold" fill="#1e293b">WaniWani</text>
506
- </svg>
507
+ <span class="logo">WaniWani</span>
507
508
  <div class="icon-circle">
508
509
  ${isSuccess ? '<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"></path></svg>' : '<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg>'}
509
510
  </div>
@@ -699,6 +700,7 @@ var loginCommand = new Command3("login").description("Log in to WaniWani").optio
699
700
  apiUrl
700
701
  // RFC 8707 resource parameter
701
702
  );
703
+ await config.ensureConfigDir();
702
704
  await auth.setTokens(
703
705
  tokenResponse.access_token,
704
706
  tokenResponse.refresh_token,
@@ -861,16 +863,14 @@ async function requireMcpId(mcpId) {
861
863
  }
862
864
  return configMcpId;
863
865
  }
864
- async function requireSessionId(mcpId) {
865
- const repository = await api.get(
866
- `/api/mcp/repositories/${mcpId}`
867
- );
868
- if (!repository.activeSandbox) {
866
+ async function requireSessionId() {
867
+ const sessionId = await config.getSessionId();
868
+ if (!sessionId) {
869
869
  throw new McpError(
870
870
  "No active session. Run 'waniwani mcp dev' to start development."
871
871
  );
872
872
  }
873
- return repository.activeSandbox.id;
873
+ return sessionId;
874
874
  }
875
875
  var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
876
876
  ".png",
@@ -940,6 +940,7 @@ var deleteCommand = new Command5("delete").description("Delete the MCP (includes
940
940
  spinner.succeed("MCP deleted");
941
941
  if (await config.getMcpId() === mcpId) {
942
942
  await config.setMcpId(null);
943
+ await config.setSessionId(null);
943
944
  }
944
945
  if (json) {
945
946
  formatOutput({ deleted: mcpId }, true);
@@ -959,37 +960,26 @@ import ora3 from "ora";
959
960
 
960
961
  // src/lib/sync.ts
961
962
  import { existsSync as existsSync3 } from "fs";
962
- import { mkdir as mkdir3, readdir, readFile as readFile3, stat, writeFile as writeFile3 } from "fs/promises";
963
- import { dirname, join as join4, relative } from "path";
963
+ import { mkdir as mkdir2, readdir, readFile as readFile2, stat, writeFile as writeFile2 } from "fs/promises";
964
+ import { dirname, join as join3, relative } from "path";
964
965
  import ignore from "ignore";
965
966
  var PROJECT_DIR = ".waniwani";
966
- var SETTINGS_FILE = "settings.json";
967
967
  async function findProjectRoot(startDir) {
968
968
  let current = startDir;
969
969
  const root = dirname(current);
970
970
  while (current !== root) {
971
- if (existsSync3(join4(current, PROJECT_DIR))) {
971
+ if (existsSync3(join3(current, PROJECT_DIR))) {
972
972
  return current;
973
973
  }
974
974
  const parent = dirname(current);
975
975
  if (parent === current) break;
976
976
  current = parent;
977
977
  }
978
- if (existsSync3(join4(current, PROJECT_DIR))) {
978
+ if (existsSync3(join3(current, PROJECT_DIR))) {
979
979
  return current;
980
980
  }
981
981
  return null;
982
982
  }
983
- async function loadProjectMcpId(projectRoot) {
984
- const settingsPath = join4(projectRoot, PROJECT_DIR, SETTINGS_FILE);
985
- try {
986
- const content = await readFile3(settingsPath, "utf-8");
987
- const settings = JSON.parse(content);
988
- return settings.mcp?.id ?? null;
989
- } catch {
990
- return null;
991
- }
992
- }
993
983
  var DEFAULT_IGNORE_PATTERNS = [
994
984
  ".waniwani",
995
985
  ".git",
@@ -1009,10 +999,10 @@ var DEFAULT_IGNORE_PATTERNS = [
1009
999
  async function loadIgnorePatterns(projectRoot) {
1010
1000
  const ig = ignore();
1011
1001
  ig.add(DEFAULT_IGNORE_PATTERNS);
1012
- const gitignorePath = join4(projectRoot, ".gitignore");
1002
+ const gitignorePath = join3(projectRoot, ".gitignore");
1013
1003
  if (existsSync3(gitignorePath)) {
1014
1004
  try {
1015
- const content = await readFile3(gitignorePath, "utf-8");
1005
+ const content = await readFile2(gitignorePath, "utf-8");
1016
1006
  ig.add(content);
1017
1007
  } catch {
1018
1008
  }
@@ -1025,7 +1015,7 @@ async function collectFiles(projectRoot) {
1025
1015
  async function walk(dir) {
1026
1016
  const entries = await readdir(dir, { withFileTypes: true });
1027
1017
  for (const entry of entries) {
1028
- const fullPath = join4(dir, entry.name);
1018
+ const fullPath = join3(dir, entry.name);
1029
1019
  const relativePath = relative(projectRoot, fullPath);
1030
1020
  if (ig.ignores(relativePath)) {
1031
1021
  continue;
@@ -1034,7 +1024,7 @@ async function collectFiles(projectRoot) {
1034
1024
  await walk(fullPath);
1035
1025
  } else if (entry.isFile()) {
1036
1026
  try {
1037
- const content = await readFile3(fullPath);
1027
+ const content = await readFile2(fullPath);
1038
1028
  const isBinary = isBinaryPath(fullPath) || detectBinary(content);
1039
1029
  files.push({
1040
1030
  path: relativePath,
@@ -1055,20 +1045,20 @@ async function pullFilesFromGithub(mcpId, targetDir) {
1055
1045
  );
1056
1046
  const writtenFiles = [];
1057
1047
  for (const file of result.files) {
1058
- const localPath = join4(targetDir, file.path);
1048
+ const localPath = join3(targetDir, file.path);
1059
1049
  const dir = dirname(localPath);
1060
- await mkdir3(dir, { recursive: true });
1050
+ await mkdir2(dir, { recursive: true });
1061
1051
  if (file.encoding === "base64") {
1062
- await writeFile3(localPath, Buffer.from(file.content, "base64"));
1052
+ await writeFile2(localPath, Buffer.from(file.content, "base64"));
1063
1053
  } else {
1064
- await writeFile3(localPath, file.content, "utf8");
1054
+ await writeFile2(localPath, file.content, "utf8");
1065
1055
  }
1066
1056
  writtenFiles.push(file.path);
1067
1057
  }
1068
1058
  return { count: writtenFiles.length, files: writtenFiles };
1069
1059
  }
1070
1060
  async function collectSingleFile(projectRoot, filePath) {
1071
- const fullPath = join4(projectRoot, filePath);
1061
+ const fullPath = join3(projectRoot, filePath);
1072
1062
  const relativePath = relative(projectRoot, fullPath);
1073
1063
  if (!existsSync3(fullPath)) {
1074
1064
  return null;
@@ -1078,7 +1068,7 @@ async function collectSingleFile(projectRoot, filePath) {
1078
1068
  if (!fileStat.isFile()) {
1079
1069
  return null;
1080
1070
  }
1081
- const content = await readFile3(fullPath);
1071
+ const content = await readFile2(fullPath);
1082
1072
  const isBinary = isBinaryPath(fullPath) || detectBinary(content);
1083
1073
  return {
1084
1074
  path: relativePath,
@@ -1152,9 +1142,6 @@ var devCommand = new Command7("dev").description("Start live development with sa
1152
1142
  );
1153
1143
  }
1154
1144
  let mcpId = options.mcpId;
1155
- if (!mcpId) {
1156
- mcpId = await loadProjectMcpId(projectRoot);
1157
- }
1158
1145
  if (!mcpId) {
1159
1146
  mcpId = await config.getMcpId();
1160
1147
  }
@@ -1182,6 +1169,7 @@ var devCommand = new Command7("dev").description("Start live development with sa
1182
1169
  }
1183
1170
  sessionId = existing.id;
1184
1171
  }
1172
+ await config.setSessionId(sessionId);
1185
1173
  spinner.text = "Syncing files to sandbox...";
1186
1174
  const files = await collectFiles(projectRoot);
1187
1175
  if (files.length > 0) {
@@ -1270,8 +1258,8 @@ var listCommand = new Command8("list").description("List files in the MCP sandbo
1270
1258
  const globalOptions = command.optsWithGlobals();
1271
1259
  const json = globalOptions.json ?? false;
1272
1260
  try {
1273
- const mcpId = await requireMcpId(options.mcpId);
1274
- const sessionId = await requireSessionId(mcpId);
1261
+ await requireMcpId(options.mcpId);
1262
+ const sessionId = await requireSessionId();
1275
1263
  const spinner = ora5(`Listing ${path}...`).start();
1276
1264
  const result = await api.get(
1277
1265
  `/api/mcp/sessions/${sessionId}/files/list?path=${encodeURIComponent(path)}`
@@ -1308,15 +1296,15 @@ function formatSize(bytes) {
1308
1296
  }
1309
1297
 
1310
1298
  // src/commands/mcp/file/read.ts
1311
- import { writeFile as writeFile4 } from "fs/promises";
1299
+ import { writeFile as writeFile3 } from "fs/promises";
1312
1300
  import { Command as Command9 } from "commander";
1313
1301
  import ora6 from "ora";
1314
1302
  var readCommand = new Command9("read").description("Read a file from the MCP sandbox").argument("<path>", "Path in sandbox (e.g., /app/src/index.ts)").option("--mcp-id <id>", "Specific MCP ID").option("--output <file>", "Write to local file instead of stdout").option("--base64", "Output as base64 (for binary files)").action(async (path, options, command) => {
1315
1303
  const globalOptions = command.optsWithGlobals();
1316
1304
  const json = globalOptions.json ?? false;
1317
1305
  try {
1318
- const mcpId = await requireMcpId(options.mcpId);
1319
- const sessionId = await requireSessionId(mcpId);
1306
+ await requireMcpId(options.mcpId);
1307
+ const sessionId = await requireSessionId();
1320
1308
  const encoding = options.base64 ? "base64" : "utf8";
1321
1309
  const spinner = ora6(`Reading ${path}...`).start();
1322
1310
  const result = await api.get(
@@ -1328,7 +1316,7 @@ var readCommand = new Command9("read").description("Read a file from the MCP san
1328
1316
  }
1329
1317
  if (options.output) {
1330
1318
  const buffer = result.encoding === "base64" ? Buffer.from(result.content, "base64") : Buffer.from(result.content, "utf8");
1331
- await writeFile4(options.output, buffer);
1319
+ await writeFile3(options.output, buffer);
1332
1320
  if (json) {
1333
1321
  formatOutput({ path, savedTo: options.output }, true);
1334
1322
  } else {
@@ -1349,15 +1337,15 @@ var readCommand = new Command9("read").description("Read a file from the MCP san
1349
1337
  });
1350
1338
 
1351
1339
  // src/commands/mcp/file/write.ts
1352
- import { readFile as readFile4 } from "fs/promises";
1340
+ import { readFile as readFile3 } from "fs/promises";
1353
1341
  import { Command as Command10 } from "commander";
1354
1342
  import ora7 from "ora";
1355
1343
  var writeCommand = new Command10("write").description("Write a file to the MCP sandbox").argument("<path>", "Path in sandbox (e.g., /app/src/index.ts)").option("--mcp-id <id>", "Specific MCP ID").option("--content <content>", "Content to write").option("--file <localFile>", "Local file to upload").option("--base64", "Treat content as base64 encoded").action(async (path, options, command) => {
1356
1344
  const globalOptions = command.optsWithGlobals();
1357
1345
  const json = globalOptions.json ?? false;
1358
1346
  try {
1359
- const mcpId = await requireMcpId(options.mcpId);
1360
- const sessionId = await requireSessionId(mcpId);
1347
+ await requireMcpId(options.mcpId);
1348
+ const sessionId = await requireSessionId();
1361
1349
  let content;
1362
1350
  let encoding = "utf8";
1363
1351
  if (options.content) {
@@ -1366,7 +1354,7 @@ var writeCommand = new Command10("write").description("Write a file to the MCP s
1366
1354
  encoding = "base64";
1367
1355
  }
1368
1356
  } else if (options.file) {
1369
- const fileBuffer = await readFile4(options.file);
1357
+ const fileBuffer = await readFile3(options.file);
1370
1358
  if (options.base64) {
1371
1359
  content = fileBuffer.toString("base64");
1372
1360
  encoding = "base64";
@@ -1403,20 +1391,20 @@ var fileCommand = new Command11("file").description("File operations in MCP sand
1403
1391
 
1404
1392
  // src/commands/mcp/init.ts
1405
1393
  import { existsSync as existsSync4 } from "fs";
1406
- import { readFile as readFile5 } from "fs/promises";
1407
- import { join as join5 } from "path";
1394
+ import { readFile as readFile4 } from "fs/promises";
1395
+ import { join as join4 } from "path";
1408
1396
  import { Command as Command12 } from "commander";
1409
1397
  import { execa } from "execa";
1410
1398
  import ora8 from "ora";
1411
1399
  async function loadParentConfig(cwd) {
1412
- const parentConfigPath = join5(cwd, LOCAL_CONFIG_DIR, CONFIG_FILE_NAME);
1400
+ const parentConfigPath = join4(cwd, LOCAL_CONFIG_DIR, CONFIG_FILE_NAME);
1413
1401
  if (!existsSync4(parentConfigPath)) {
1414
1402
  return null;
1415
1403
  }
1416
1404
  try {
1417
- const content = await readFile5(parentConfigPath, "utf-8");
1405
+ const content = await readFile4(parentConfigPath, "utf-8");
1418
1406
  const config2 = JSON.parse(content);
1419
- const { mcp: _, ...rest } = config2;
1407
+ const { mcpId: _, sessionId: __, ...rest } = config2;
1420
1408
  return rest;
1421
1409
  } catch {
1422
1410
  return null;
@@ -1427,7 +1415,7 @@ var initCommand = new Command12("init").description("Create a new MCP project").
1427
1415
  const json = globalOptions.json ?? false;
1428
1416
  try {
1429
1417
  const cwd = process.cwd();
1430
- const projectDir = join5(cwd, name);
1418
+ const projectDir = join4(cwd, name);
1431
1419
  if (existsSync4(projectDir)) {
1432
1420
  if (json) {
1433
1421
  formatOutput(
@@ -1454,10 +1442,7 @@ var initCommand = new Command12("init").description("Create a new MCP project").
1454
1442
  const parentConfig = await loadParentConfig(cwd);
1455
1443
  await initConfigAt(projectDir, {
1456
1444
  ...parentConfig,
1457
- mcp: {
1458
- id: result.repository.id,
1459
- name: result.repository.name
1460
- }
1445
+ mcpId: result.repository.id
1461
1446
  });
1462
1447
  spinner.succeed("MCP project created");
1463
1448
  } else {
@@ -1579,8 +1564,8 @@ var logsCommand = new Command14("logs").description("Stream logs from the MCP se
1579
1564
  process.on("SIGINT", cleanup);
1580
1565
  process.on("SIGTERM", cleanup);
1581
1566
  try {
1582
- const mcpId = await requireMcpId(options.mcpId);
1583
- const sessionId = await requireSessionId(mcpId);
1567
+ await requireMcpId(options.mcpId);
1568
+ const sessionId = await requireSessionId();
1584
1569
  const token = await auth.getAccessToken();
1585
1570
  if (!token) {
1586
1571
  throw new AuthError(
@@ -1715,8 +1700,8 @@ var runCommandCommand = new Command15("run-command").description("Run a command
1715
1700
  const globalOptions = command.optsWithGlobals();
1716
1701
  const json = globalOptions.json ?? false;
1717
1702
  try {
1718
- const mcpId = await requireMcpId(options.mcpId);
1719
- const sessionId = await requireSessionId(mcpId);
1703
+ await requireMcpId(options.mcpId);
1704
+ const sessionId = await requireSessionId();
1720
1705
  const timeout = options.timeout ? Number.parseInt(options.timeout, 10) : void 0;
1721
1706
  const spinner = ora11(`Running: ${cmd} ${args.join(" ")}`.trim()).start();
1722
1707
  const result = await api.post(
@@ -1847,8 +1832,8 @@ var stopCommand = new Command17("stop").description("Stop the development enviro
1847
1832
  const globalOptions = command.optsWithGlobals();
1848
1833
  const json = globalOptions.json ?? false;
1849
1834
  try {
1850
- const mcpId = await requireMcpId(options.mcpId);
1851
- const sessionId = await requireSessionId(mcpId);
1835
+ await requireMcpId(options.mcpId);
1836
+ const sessionId = await requireSessionId();
1852
1837
  const spinner = ora13("Stopping development environment...").start();
1853
1838
  try {
1854
1839
  await api.post(`/api/mcp/sessions/${sessionId}/server`, {
@@ -1857,6 +1842,7 @@ var stopCommand = new Command17("stop").description("Stop the development enviro
1857
1842
  } catch {
1858
1843
  }
1859
1844
  await api.delete(`/api/mcp/sessions/${sessionId}`);
1845
+ await config.setSessionId(null);
1860
1846
  spinner.succeed("Development environment stopped");
1861
1847
  if (json) {
1862
1848
  formatOutput({ stopped: true }, true);
@@ -1910,7 +1896,7 @@ var syncCommand = new Command18("sync").description("Pull files from GitHub to l
1910
1896
  // src/commands/mcp/use.ts
1911
1897
  import { Command as Command19 } from "commander";
1912
1898
  import ora15 from "ora";
1913
- var useCommand = new Command19("use").description("Select an MCP to use for subsequent commands").argument("<name>", "Name of the MCP to use").option("--global", "Save to global config instead of project config").action(async (name, options, command) => {
1899
+ var useCommand = new Command19("use").description("Select an MCP to use for subsequent commands").argument("<name>", "Name of the MCP to use").action(async (name, _options, command) => {
1914
1900
  const globalOptions = command.optsWithGlobals();
1915
1901
  const json = globalOptions.json ?? false;
1916
1902
  try {
@@ -1925,12 +1911,12 @@ var useCommand = new Command19("use").description("Select an MCP to use for subs
1925
1911
  `MCP "${name}" not found. Run 'waniwani mcp list' to see available MCPs.`
1926
1912
  );
1927
1913
  }
1928
- const cfg = options.global ? globalConfig : config;
1929
- await cfg.setMcpId(mcp.id);
1914
+ await config.setMcpId(mcp.id);
1915
+ await config.setSessionId(null);
1930
1916
  if (json) {
1931
- formatOutput({ selected: mcp, scope: cfg.scope }, true);
1917
+ formatOutput({ selected: mcp }, true);
1932
1918
  } else {
1933
- formatSuccess(`Now using MCP "${name}" (${cfg.scope})`, false);
1919
+ formatSuccess(`Now using MCP "${name}"`, false);
1934
1920
  console.log();
1935
1921
  console.log(` MCP ID: ${mcp.id}`);
1936
1922
  console.log();