@niroai/niro 0.9.0 → 0.10.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/CHANGELOG.md +69 -0
- package/README.md +131 -211
- package/package.json +1 -1
- package/src/commands/ab.js +198 -0
- package/src/commands/add-project.js +11 -11
- package/src/commands/add-repo.js +23 -23
- package/src/commands/build.js +5 -5
- package/src/commands/delete.js +3 -3
- package/src/commands/edit.js +11 -11
- package/src/commands/info.js +2 -2
- package/src/commands/init.js +108 -87
- package/src/commands/login.js +25 -5
- package/src/commands/projects.js +1 -1
- package/src/commands/release.js +7 -7
- package/src/commands/remove.js +5 -5
- package/src/commands/start.js +567 -0
- package/src/commands/takeover.js +19 -19
- package/src/commands/watch.js +35 -35
- package/src/index.js +57 -3
- package/src/lib/folderSync.js +13 -8
- package/src/lib/moduleExcludeSuggestions.js +5 -5
- package/src/lib/nestedOutput.js +49 -0
- package/src/lib/onboardTarget.js +5 -5
- package/src/lib/prompt.js +3 -0
- package/src/lib/service.js +20 -12
- package/src/lib/spinner.js +28 -7
- package/src/lib/watchDaemon.js +9 -9
- package/src/mcp/setup.js +198 -160
- package/src/mcp/teardown.js +53 -53
package/src/mcp/teardown.js
CHANGED
|
@@ -207,7 +207,7 @@ function deleteFileIfPresent(absPath, label) {
|
|
|
207
207
|
try {
|
|
208
208
|
if (!fs.existsSync(absPath)) return false;
|
|
209
209
|
fs.rmSync(absPath, { force: true });
|
|
210
|
-
console.log(`
|
|
210
|
+
console.log(` Removed ${label}: ${absPath}`);
|
|
211
211
|
// Clean up a now-empty generated skill dir (…/skills/niro-skill/).
|
|
212
212
|
try {
|
|
213
213
|
const parent = path.dirname(absPath);
|
|
@@ -217,7 +217,7 @@ function deleteFileIfPresent(absPath, label) {
|
|
|
217
217
|
}
|
|
218
218
|
return true;
|
|
219
219
|
} catch (e) {
|
|
220
|
-
console.warn(`
|
|
220
|
+
console.warn(` Could not remove ${label} (${absPath}): ${e.message}`);
|
|
221
221
|
return false;
|
|
222
222
|
}
|
|
223
223
|
}
|
|
@@ -228,17 +228,17 @@ function stripMarkerFromFile(absPath, label) {
|
|
|
228
228
|
try {
|
|
229
229
|
content = fs.readFileSync(absPath, "utf-8");
|
|
230
230
|
} catch (e) {
|
|
231
|
-
console.warn(`
|
|
231
|
+
console.warn(` Could not read ${absPath}: ${e.message}`);
|
|
232
232
|
return false;
|
|
233
233
|
}
|
|
234
234
|
const { content: next, removed } = removeMarkerSection(content, NIRO_MD_MARKER);
|
|
235
235
|
if (!removed) return false;
|
|
236
236
|
try {
|
|
237
237
|
fs.writeFileSync(absPath, next);
|
|
238
|
-
console.log(`
|
|
238
|
+
console.log(` Removed niro section from ${label}: ${absPath}`);
|
|
239
239
|
return true;
|
|
240
240
|
} catch (e) {
|
|
241
|
-
console.warn(`
|
|
241
|
+
console.warn(` Could not write ${absPath}: ${e.message}`);
|
|
242
242
|
return false;
|
|
243
243
|
}
|
|
244
244
|
}
|
|
@@ -249,44 +249,44 @@ function stripNiroHooksFromSettings(absPath) {
|
|
|
249
249
|
try {
|
|
250
250
|
settings = JSON.parse(fs.readFileSync(absPath, "utf-8"));
|
|
251
251
|
} catch (e) {
|
|
252
|
-
console.warn(`
|
|
252
|
+
console.warn(` Could not parse ${absPath}: ${e.message}. Leaving it untouched.`);
|
|
253
253
|
return false;
|
|
254
254
|
}
|
|
255
255
|
const { removed } = filterNiroHooks(settings);
|
|
256
256
|
if (!removed) return false;
|
|
257
257
|
try {
|
|
258
258
|
fs.writeFileSync(absPath, JSON.stringify(settings, null, 2) + "\n");
|
|
259
|
-
console.log(`
|
|
259
|
+
console.log(` Removed ${removed} niro hook(s) from ${absPath}`);
|
|
260
260
|
return true;
|
|
261
261
|
} catch (e) {
|
|
262
|
-
console.warn(`
|
|
262
|
+
console.warn(` Could not write ${absPath}: ${e.message}`);
|
|
263
263
|
return false;
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
function removeNiroFromJsonConfig(absPath, label, topLevelKey = "mcpServers") {
|
|
268
268
|
if (!fs.existsSync(absPath)) {
|
|
269
|
-
console.log(`
|
|
269
|
+
console.log(` ${label} MCP config not found. Skipping (${absPath}).`);
|
|
270
270
|
return false;
|
|
271
271
|
}
|
|
272
272
|
let config;
|
|
273
273
|
try {
|
|
274
274
|
config = JSON.parse(fs.readFileSync(absPath, "utf-8"));
|
|
275
275
|
} catch (e) {
|
|
276
|
-
console.warn(`
|
|
276
|
+
console.warn(` Could not parse ${absPath}: ${e.message}. Leaving it untouched.`);
|
|
277
277
|
return false;
|
|
278
278
|
}
|
|
279
279
|
const { removed } = removeMcpServerEntry(config, topLevelKey);
|
|
280
280
|
if (!removed) {
|
|
281
|
-
console.log(`
|
|
281
|
+
console.log(` No niro MCP entry in ${label} config. Skipping.`);
|
|
282
282
|
return false;
|
|
283
283
|
}
|
|
284
284
|
try {
|
|
285
285
|
fs.writeFileSync(absPath, JSON.stringify(config, null, 2) + "\n");
|
|
286
|
-
console.log(`
|
|
286
|
+
console.log(` Removed niro MCP entry from ${label}: ${absPath}`);
|
|
287
287
|
return true;
|
|
288
288
|
} catch (e) {
|
|
289
|
-
console.warn(`
|
|
289
|
+
console.warn(` Could not write ${absPath}: ${e.message}`);
|
|
290
290
|
return false;
|
|
291
291
|
}
|
|
292
292
|
}
|
|
@@ -297,17 +297,17 @@ function removeCursorPermissions(absPath) {
|
|
|
297
297
|
try {
|
|
298
298
|
data = JSON.parse(fs.readFileSync(absPath, "utf-8"));
|
|
299
299
|
} catch (e) {
|
|
300
|
-
console.warn(`
|
|
300
|
+
console.warn(` Could not parse ${absPath}: ${e.message}. Leaving it untouched.`);
|
|
301
301
|
return false;
|
|
302
302
|
}
|
|
303
303
|
const { removed } = removeNiroFromCursorAllowlist(data);
|
|
304
304
|
if (!removed) return false;
|
|
305
305
|
try {
|
|
306
306
|
fs.writeFileSync(absPath, JSON.stringify(data, null, 2) + "\n");
|
|
307
|
-
console.log(`
|
|
307
|
+
console.log(` Removed "niro:*" from Cursor permissions: ${absPath}`);
|
|
308
308
|
return true;
|
|
309
309
|
} catch (e) {
|
|
310
|
-
console.warn(`
|
|
310
|
+
console.warn(` Could not write ${absPath}: ${e.message}`);
|
|
311
311
|
return false;
|
|
312
312
|
}
|
|
313
313
|
}
|
|
@@ -322,7 +322,7 @@ function runMcpRemove(cmd, args) {
|
|
|
322
322
|
execSync([cmd, ...args].join(" "), { stdio: "inherit" });
|
|
323
323
|
return true;
|
|
324
324
|
} catch {
|
|
325
|
-
console.log(`
|
|
325
|
+
console.log(` (${cmd} unavailable or niro already unregistered. Skipping.)`);
|
|
326
326
|
return false;
|
|
327
327
|
}
|
|
328
328
|
}
|
|
@@ -358,7 +358,7 @@ function isClientConfigured(clientId) {
|
|
|
358
358
|
function removeSharedAgentsSkills(forClientId) {
|
|
359
359
|
const other = forClientId === "codex" ? "windsurf" : "codex";
|
|
360
360
|
if (isClientConfigured(other)) {
|
|
361
|
-
console.log(`
|
|
361
|
+
console.log(` Keeping shared ~/.agents/skills, still used by ${other} (use --all to remove everything).`);
|
|
362
362
|
return;
|
|
363
363
|
}
|
|
364
364
|
forceRemoveAgentsSkills();
|
|
@@ -379,7 +379,7 @@ function forceRemoveAgentsSkills() {
|
|
|
379
379
|
// ─── per-client uninstallers (mirror setup.js's per-client installers) ────────
|
|
380
380
|
|
|
381
381
|
function uninstallClaudeCode() {
|
|
382
|
-
console.log("\n
|
|
382
|
+
console.log("\n Removing Niro from Claude Code...\n");
|
|
383
383
|
const home = userHome();
|
|
384
384
|
runMcpRemove("claude", ["mcp", "remove", "niro", "--scope", "user"]);
|
|
385
385
|
stripNiroHooksFromSettings(path.join(home, ".claude", "settings.json"));
|
|
@@ -397,7 +397,7 @@ function uninstallClaudeCode() {
|
|
|
397
397
|
}
|
|
398
398
|
|
|
399
399
|
function uninstallCodex(opts = {}) {
|
|
400
|
-
console.log("\n
|
|
400
|
+
console.log("\n Removing Niro from Codex...\n");
|
|
401
401
|
const home = userHome();
|
|
402
402
|
// codex mcp remove drops the whole [mcp_servers.niro] table, incl. the approval-mode line.
|
|
403
403
|
runMcpRemove("codex", ["mcp", "remove", "niro"]);
|
|
@@ -407,12 +407,12 @@ function uninstallCodex(opts = {}) {
|
|
|
407
407
|
}
|
|
408
408
|
|
|
409
409
|
function uninstallClaudeDesktop() {
|
|
410
|
-
console.log("\n
|
|
410
|
+
console.log("\n Removing Niro from Claude Desktop...\n");
|
|
411
411
|
removeNiroFromJsonConfig(CLIENTS["claude-desktop"].configPath(), "Claude Desktop");
|
|
412
412
|
}
|
|
413
413
|
|
|
414
414
|
function uninstallCursor() {
|
|
415
|
-
console.log("\n
|
|
415
|
+
console.log("\n Removing Niro from Cursor...\n");
|
|
416
416
|
const home = userHome();
|
|
417
417
|
removeNiroFromJsonConfig(CLIENTS.cursor.configPath(), "Cursor");
|
|
418
418
|
removeCursorPermissions(path.join(home, ".cursor", "permissions.json"));
|
|
@@ -421,7 +421,7 @@ function uninstallCursor() {
|
|
|
421
421
|
}
|
|
422
422
|
|
|
423
423
|
function uninstallWindsurf(opts = {}) {
|
|
424
|
-
console.log("\n
|
|
424
|
+
console.log("\n Removing Niro from Windsurf...\n");
|
|
425
425
|
const home = userHome();
|
|
426
426
|
removeNiroFromJsonConfig(CLIENTS.windsurf.configPath(), "Windsurf");
|
|
427
427
|
stripMarkerFromFile(path.join(home, ".codeium", "windsurf", "memories", "global_rules.md"), "Windsurf global rules");
|
|
@@ -430,41 +430,41 @@ function uninstallWindsurf(opts = {}) {
|
|
|
430
430
|
}
|
|
431
431
|
|
|
432
432
|
function uninstallVsCode() {
|
|
433
|
-
console.log("\n
|
|
433
|
+
console.log("\n Removing Niro from VS Code...\n");
|
|
434
434
|
removeNiroFromJsonConfig(CLIENTS.vscode.configPath(), "VS Code", "servers");
|
|
435
435
|
}
|
|
436
436
|
|
|
437
437
|
function uninstallGeminiCli() {
|
|
438
|
-
console.log("\n
|
|
438
|
+
console.log("\n Removing Niro from Gemini CLI...\n");
|
|
439
439
|
runMcpRemove("gemini", ["mcp", "remove", "-s", "user", "niro"]);
|
|
440
440
|
stripMarkerFromFile(path.join(userHome(), ".gemini", "GEMINI.md"), "Gemini CLI memory");
|
|
441
441
|
}
|
|
442
442
|
|
|
443
443
|
function uninstallCopilotCli() {
|
|
444
|
-
console.log("\n
|
|
444
|
+
console.log("\n Removing Niro from GitHub Copilot CLI...\n");
|
|
445
445
|
runMcpRemove("copilot", ["mcp", "remove", "niro"]);
|
|
446
446
|
stripMarkerFromFile(path.join(userHome(), ".copilot", "copilot-instructions.md"), "Copilot CLI instructions");
|
|
447
447
|
}
|
|
448
448
|
|
|
449
449
|
function uninstallFactory() {
|
|
450
|
-
console.log("\n
|
|
450
|
+
console.log("\n Removing Niro from Factory (droid)...\n");
|
|
451
451
|
runMcpRemove("droid", ["mcp", "remove", "niro"]);
|
|
452
452
|
stripMarkerFromFile(path.join(userHome(), ".factory", "AGENTS.md"), "Factory AGENTS.md");
|
|
453
453
|
}
|
|
454
454
|
|
|
455
455
|
function uninstallGoose() {
|
|
456
|
-
console.log("\n
|
|
456
|
+
console.log("\n Removing Niro from Goose...\n");
|
|
457
457
|
const { gooseConfigPath } = require("./setup");
|
|
458
458
|
const configPath = gooseConfigPath();
|
|
459
459
|
if (!fs.existsSync(configPath)) {
|
|
460
|
-
console.log(`
|
|
460
|
+
console.log(` Goose config not found. Skipping (${configPath}).`);
|
|
461
461
|
return;
|
|
462
462
|
}
|
|
463
463
|
let content;
|
|
464
464
|
try {
|
|
465
465
|
content = fs.readFileSync(configPath, "utf-8");
|
|
466
466
|
} catch (e) {
|
|
467
|
-
console.warn(`
|
|
467
|
+
console.warn(` Could not read ${configPath}: ${e.message}. Leaving it untouched.`);
|
|
468
468
|
return;
|
|
469
469
|
}
|
|
470
470
|
// Mirrors the bounded block install wrote: the " niro:" entry and everything indented
|
|
@@ -473,7 +473,7 @@ function uninstallGoose() {
|
|
|
473
473
|
const lines = content.split(/\r?\n/);
|
|
474
474
|
const start = lines.findIndex((l) => /^ {2}niro:\s*$/.test(l));
|
|
475
475
|
if (start === -1) {
|
|
476
|
-
console.log("
|
|
476
|
+
console.log(" No `niro` extension entry in Goose config. Skipping.");
|
|
477
477
|
return;
|
|
478
478
|
}
|
|
479
479
|
let end = start + 1;
|
|
@@ -481,26 +481,26 @@ function uninstallGoose() {
|
|
|
481
481
|
lines.splice(start, end - start);
|
|
482
482
|
try {
|
|
483
483
|
fs.writeFileSync(configPath, lines.join(eol));
|
|
484
|
-
console.log(`
|
|
484
|
+
console.log(` Removed niro extension from Goose config: ${configPath}`);
|
|
485
485
|
} catch (e) {
|
|
486
|
-
console.warn(`
|
|
486
|
+
console.warn(` Could not write ${configPath}: ${e.message}`);
|
|
487
487
|
}
|
|
488
488
|
}
|
|
489
489
|
|
|
490
490
|
function uninstallOpenCode() {
|
|
491
|
-
console.log("\n
|
|
491
|
+
console.log("\n Removing Niro from OpenCode...\n");
|
|
492
492
|
removeNiroFromJsonConfig(CLIENTS.opencode.configPath(), "OpenCode", "mcp");
|
|
493
493
|
stripMarkerFromFile(path.join(userHome(), ".config", "opencode", "AGENTS.md"), "OpenCode AGENTS.md");
|
|
494
494
|
}
|
|
495
495
|
|
|
496
496
|
function uninstallCline() {
|
|
497
|
-
console.log("\n
|
|
497
|
+
console.log("\n Removing Niro from Cline...\n");
|
|
498
498
|
removeNiroFromJsonConfig(CLIENTS.cline.configPath(), "Cline");
|
|
499
499
|
deleteFileIfPresent(path.join(userHome(), "Documents", "Cline", "Rules", "niro.md"), "Cline rule");
|
|
500
500
|
}
|
|
501
501
|
|
|
502
502
|
function uninstallKiro() {
|
|
503
|
-
console.log("\n
|
|
503
|
+
console.log("\n Removing Niro from Kiro...\n");
|
|
504
504
|
removeNiroFromJsonConfig(CLIENTS.kiro.configPath(), "Kiro");
|
|
505
505
|
deleteFileIfPresent(path.join(userHome(), ".kiro", "steering", "niro.md"), "Kiro steering file");
|
|
506
506
|
}
|
|
@@ -514,7 +514,7 @@ function uninstallKiro() {
|
|
|
514
514
|
* either file is always found.
|
|
515
515
|
*/
|
|
516
516
|
function uninstallAntigravity() {
|
|
517
|
-
console.log("\n
|
|
517
|
+
console.log("\n Removing Niro from Antigravity...\n");
|
|
518
518
|
const home = userHome();
|
|
519
519
|
const legacy = path.join(home, ".gemini", "antigravity", "mcp_config.json");
|
|
520
520
|
const unified = path.join(home, ".gemini", "config", "mcp_config.json");
|
|
@@ -557,9 +557,9 @@ function removeGlobalMcpServerUrl() {
|
|
|
557
557
|
if (!Object.prototype.hasOwnProperty.call(current, "mcpServerUrl")) return;
|
|
558
558
|
delete current.mcpServerUrl;
|
|
559
559
|
fs.writeFileSync(cfg.FILE, JSON.stringify(current, null, 2) + "\n");
|
|
560
|
-
console.log(`
|
|
560
|
+
console.log(` Removed mcpServerUrl from ${cfg.FILE}`);
|
|
561
561
|
} catch (e) {
|
|
562
|
-
console.warn(`
|
|
562
|
+
console.warn(` Could not update ~/.niro/config.json: ${e.message}`);
|
|
563
563
|
}
|
|
564
564
|
}
|
|
565
565
|
|
|
@@ -567,13 +567,13 @@ function removeGlobalMcpServerUrl() {
|
|
|
567
567
|
|
|
568
568
|
function printHeader() {
|
|
569
569
|
console.log("");
|
|
570
|
-
console.log("
|
|
571
|
-
console.log("
|
|
570
|
+
console.log(" Niro MCP Server Uninstall");
|
|
571
|
+
console.log(" -------------------------");
|
|
572
572
|
console.log("");
|
|
573
573
|
}
|
|
574
574
|
|
|
575
575
|
function printClients() {
|
|
576
|
-
console.log("
|
|
576
|
+
console.log(" Clients:");
|
|
577
577
|
Object.keys(UNINSTALLERS).forEach((id) => {
|
|
578
578
|
const c = CLIENTS[id];
|
|
579
579
|
console.log(` ${id.padEnd(18)} ${c ? c.name : id}`);
|
|
@@ -607,9 +607,9 @@ function runUninstall(targets, isFull) {
|
|
|
607
607
|
removeGlobalMcpServerUrl();
|
|
608
608
|
}
|
|
609
609
|
|
|
610
|
-
console.log("\n
|
|
611
|
-
console.log("
|
|
612
|
-
console.log("
|
|
610
|
+
console.log("\n Uninstall complete. Restart your AI assistant for the change to take effect.\n");
|
|
611
|
+
console.log(" Your `niro login` session is kept. Run `niro logout` to clear it.");
|
|
612
|
+
console.log(" The `niro` command itself is still installed. To remove it too:");
|
|
613
613
|
console.log(" npm rm -g niro-mcp-and-cli\n");
|
|
614
614
|
}
|
|
615
615
|
|
|
@@ -633,25 +633,25 @@ async function main() {
|
|
|
633
633
|
targets = allIds;
|
|
634
634
|
} else if (clientArg) {
|
|
635
635
|
if (!UNINSTALLERS[clientArg]) {
|
|
636
|
-
console.error(`
|
|
636
|
+
console.error(` Unknown client: ${clientArg}\n`);
|
|
637
637
|
printClients();
|
|
638
638
|
process.exit(1);
|
|
639
639
|
}
|
|
640
640
|
targets = [clientArg];
|
|
641
641
|
} else if (!process.stdin.isTTY) {
|
|
642
642
|
// Non-interactive with no target: refuse rather than guess.
|
|
643
|
-
console.error("
|
|
643
|
+
console.error(" No client specified. Pass --client <id> or --all.\n");
|
|
644
644
|
printClients();
|
|
645
645
|
process.exit(1);
|
|
646
646
|
} else {
|
|
647
647
|
printClients();
|
|
648
648
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
649
|
-
const choice = await ask(rl, "
|
|
649
|
+
const choice = await ask(rl, " Remove Niro from which client?", "claude-code");
|
|
650
650
|
rl.close();
|
|
651
651
|
if (choice === "all") targets = allIds;
|
|
652
652
|
else if (UNINSTALLERS[choice]) targets = [choice];
|
|
653
653
|
else {
|
|
654
|
-
console.error(`\n
|
|
654
|
+
console.error(`\n Unknown client: ${choice}\n`);
|
|
655
655
|
process.exit(1);
|
|
656
656
|
}
|
|
657
657
|
}
|
|
@@ -659,13 +659,13 @@ async function main() {
|
|
|
659
659
|
const isFull = targets.length === allIds.length;
|
|
660
660
|
|
|
661
661
|
if (!assumeYes && process.stdin.isTTY) {
|
|
662
|
-
console.log(`\n
|
|
663
|
-
console.log("
|
|
662
|
+
console.log(`\n This removes Niro MCP config from: ${targets.join(", ")}`);
|
|
663
|
+
console.log(" (Your `niro login` session in ~/.niro/credentials.json is left intact.)\n");
|
|
664
664
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
665
|
-
const ans = await ask(rl, "
|
|
665
|
+
const ans = await ask(rl, " Proceed?", "yes");
|
|
666
666
|
rl.close();
|
|
667
667
|
if (!/^y/i.test(ans)) {
|
|
668
|
-
console.log("\n
|
|
668
|
+
console.log("\n Aborted. Nothing was changed.\n");
|
|
669
669
|
return;
|
|
670
670
|
}
|
|
671
671
|
}
|