@waniwani/cli 0.0.34 → 0.0.36

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";
@@ -1402,32 +1390,31 @@ var writeCommand = new Command10("write").description("Write a file to the MCP s
1402
1390
  var fileCommand = new Command11("file").description("File operations in MCP sandbox").addCommand(readCommand).addCommand(writeCommand).addCommand(listCommand);
1403
1391
 
1404
1392
  // src/commands/mcp/init.ts
1405
- import { existsSync as existsSync4 } from "fs";
1406
- import { readFile as readFile5 } from "fs/promises";
1407
- import { join as join5 } from "path";
1393
+ import { existsSync as existsSync4, mkdirSync } from "fs";
1394
+ import { readFile as readFile4 } from "fs/promises";
1395
+ import { join as join4 } from "path";
1408
1396
  import { Command as Command12 } from "commander";
1409
- import { execa } from "execa";
1410
1397
  import ora8 from "ora";
1411
1398
  async function loadParentConfig(cwd) {
1412
- const parentConfigPath = join5(cwd, LOCAL_CONFIG_DIR, CONFIG_FILE_NAME);
1399
+ const parentConfigPath = join4(cwd, LOCAL_CONFIG_DIR, CONFIG_FILE_NAME);
1413
1400
  if (!existsSync4(parentConfigPath)) {
1414
1401
  return null;
1415
1402
  }
1416
1403
  try {
1417
- const content = await readFile5(parentConfigPath, "utf-8");
1404
+ const content = await readFile4(parentConfigPath, "utf-8");
1418
1405
  const config2 = JSON.parse(content);
1419
- const { mcp: _, ...rest } = config2;
1406
+ const { mcpId: _, sessionId: __, ...rest } = config2;
1420
1407
  return rest;
1421
1408
  } catch {
1422
1409
  return null;
1423
1410
  }
1424
1411
  }
1425
- var initCommand = new Command12("init").description("Create a new MCP project").argument("<name>", "Name for the MCP project").option("--no-clone", "Skip automatic git clone (just output the command)").action(async (name, options, command) => {
1412
+ var initCommand = new Command12("init").description("Create a new MCP project").argument("<name>", "Name for the MCP project").action(async (name, _options, command) => {
1426
1413
  const globalOptions = command.optsWithGlobals();
1427
1414
  const json = globalOptions.json ?? false;
1428
1415
  try {
1429
1416
  const cwd = process.cwd();
1430
- const projectDir = join5(cwd, name);
1417
+ const projectDir = join4(cwd, name);
1431
1418
  if (existsSync4(projectDir)) {
1432
1419
  if (json) {
1433
1420
  formatOutput(
@@ -1443,32 +1430,22 @@ var initCommand = new Command12("init").description("Create a new MCP project").
1443
1430
  process.exit(1);
1444
1431
  }
1445
1432
  const spinner = ora8("Creating MCP...").start();
1446
- const result = await api.post(
1447
- "/api/mcp/repositories",
1448
- { name }
1449
- );
1450
- if (options.clone !== false) {
1451
- spinner.text = "Cloning repository...";
1452
- await execa("git", ["clone", result.cloneUrl, name], { cwd });
1453
- spinner.text = "Setting up project config...";
1454
- const parentConfig = await loadParentConfig(cwd);
1455
- await initConfigAt(projectDir, {
1456
- ...parentConfig,
1457
- mcp: {
1458
- id: result.repository.id,
1459
- name: result.repository.name
1460
- }
1461
- });
1462
- spinner.succeed("MCP project created");
1463
- } else {
1464
- spinner.succeed("MCP created");
1465
- }
1433
+ const result = await api.post("/api/mcp/repositories", {
1434
+ name
1435
+ });
1436
+ mkdirSync(projectDir, { recursive: true });
1437
+ const parentConfig = await loadParentConfig(cwd);
1438
+ await initConfigAt(projectDir, {
1439
+ ...parentConfig,
1440
+ mcpId: result.id
1441
+ });
1442
+ spinner.succeed("MCP project created");
1466
1443
  if (json) {
1467
1444
  formatOutput(
1468
1445
  {
1469
1446
  success: true,
1470
- projectDir: options.clone !== false ? projectDir : null,
1471
- mcpId: result.repository.id
1447
+ projectDir,
1448
+ mcpId: result.id
1472
1449
  },
1473
1450
  true
1474
1451
  );
@@ -1476,24 +1453,10 @@ var initCommand = new Command12("init").description("Create a new MCP project").
1476
1453
  console.log();
1477
1454
  formatSuccess(`MCP "${name}" created!`, false);
1478
1455
  console.log();
1479
- if (options.clone !== false) {
1480
- console.log("Next steps:");
1481
- console.log(` cd ${name}`);
1482
- console.log(
1483
- " waniwani mcp dev # Start live preview with file watching"
1484
- );
1485
- console.log(" waniwani mcp push # Deploy to production");
1486
- } else {
1487
- console.log("Clone your repository:");
1488
- console.log(` ${result.cloneCommand}`);
1489
- console.log(` cd ${name}`);
1490
- console.log();
1491
- console.log("Then start developing:");
1492
- console.log(
1493
- " waniwani mcp dev # Start live preview with file watching"
1494
- );
1495
- console.log(" waniwani mcp push # Deploy to production");
1496
- }
1456
+ console.log("Next steps:");
1457
+ console.log(` cd ${name}`);
1458
+ console.log(" waniwani mcp sync # Pull template files");
1459
+ console.log(" waniwani mcp dev # Start developing");
1497
1460
  }
1498
1461
  } catch (error) {
1499
1462
  handleError(error, json);
@@ -1579,8 +1542,8 @@ var logsCommand = new Command14("logs").description("Stream logs from the MCP se
1579
1542
  process.on("SIGINT", cleanup);
1580
1543
  process.on("SIGTERM", cleanup);
1581
1544
  try {
1582
- const mcpId = await requireMcpId(options.mcpId);
1583
- const sessionId = await requireSessionId(mcpId);
1545
+ await requireMcpId(options.mcpId);
1546
+ const sessionId = await requireSessionId();
1584
1547
  const token = await auth.getAccessToken();
1585
1548
  if (!token) {
1586
1549
  throw new AuthError(
@@ -1715,8 +1678,8 @@ var runCommandCommand = new Command15("run-command").description("Run a command
1715
1678
  const globalOptions = command.optsWithGlobals();
1716
1679
  const json = globalOptions.json ?? false;
1717
1680
  try {
1718
- const mcpId = await requireMcpId(options.mcpId);
1719
- const sessionId = await requireSessionId(mcpId);
1681
+ await requireMcpId(options.mcpId);
1682
+ const sessionId = await requireSessionId();
1720
1683
  const timeout = options.timeout ? Number.parseInt(options.timeout, 10) : void 0;
1721
1684
  const spinner = ora11(`Running: ${cmd} ${args.join(" ")}`.trim()).start();
1722
1685
  const result = await api.post(
@@ -1847,8 +1810,8 @@ var stopCommand = new Command17("stop").description("Stop the development enviro
1847
1810
  const globalOptions = command.optsWithGlobals();
1848
1811
  const json = globalOptions.json ?? false;
1849
1812
  try {
1850
- const mcpId = await requireMcpId(options.mcpId);
1851
- const sessionId = await requireSessionId(mcpId);
1813
+ await requireMcpId(options.mcpId);
1814
+ const sessionId = await requireSessionId();
1852
1815
  const spinner = ora13("Stopping development environment...").start();
1853
1816
  try {
1854
1817
  await api.post(`/api/mcp/sessions/${sessionId}/server`, {
@@ -1857,6 +1820,7 @@ var stopCommand = new Command17("stop").description("Stop the development enviro
1857
1820
  } catch {
1858
1821
  }
1859
1822
  await api.delete(`/api/mcp/sessions/${sessionId}`);
1823
+ await config.setSessionId(null);
1860
1824
  spinner.succeed("Development environment stopped");
1861
1825
  if (json) {
1862
1826
  formatOutput({ stopped: true }, true);
@@ -1910,7 +1874,7 @@ var syncCommand = new Command18("sync").description("Pull files from GitHub to l
1910
1874
  // src/commands/mcp/use.ts
1911
1875
  import { Command as Command19 } from "commander";
1912
1876
  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) => {
1877
+ 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
1878
  const globalOptions = command.optsWithGlobals();
1915
1879
  const json = globalOptions.json ?? false;
1916
1880
  try {
@@ -1925,12 +1889,12 @@ var useCommand = new Command19("use").description("Select an MCP to use for subs
1925
1889
  `MCP "${name}" not found. Run 'waniwani mcp list' to see available MCPs.`
1926
1890
  );
1927
1891
  }
1928
- const cfg = options.global ? globalConfig : config;
1929
- await cfg.setMcpId(mcp.id);
1892
+ await config.setMcpId(mcp.id);
1893
+ await config.setSessionId(null);
1930
1894
  if (json) {
1931
- formatOutput({ selected: mcp, scope: cfg.scope }, true);
1895
+ formatOutput({ selected: mcp }, true);
1932
1896
  } else {
1933
- formatSuccess(`Now using MCP "${name}" (${cfg.scope})`, false);
1897
+ formatSuccess(`Now using MCP "${name}"`, false);
1934
1898
  console.log();
1935
1899
  console.log(` MCP ID: ${mcp.id}`);
1936
1900
  console.log();