@noir-ai/cli 1.2.0-beta.2 → 1.3.0-beta.2
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/bin.js +94 -21
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-7WKKZ452.js → chunk-J2Y3BOVK.js} +9 -3
- package/dist/chunk-J2Y3BOVK.js.map +1 -0
- package/dist/{chunk-I3L3KNJM.js → chunk-J5HAAQI4.js} +93 -150
- package/dist/chunk-J5HAAQI4.js.map +1 -0
- package/dist/chunk-OF4OO5W6.js +190 -0
- package/dist/chunk-OF4OO5W6.js.map +1 -0
- package/dist/{create-ZK2EBXG3.js → create-VK7JX6IB.js} +10 -4
- package/dist/create-VK7JX6IB.js.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +3 -2
- package/dist/{sync-IEH2BVXU.js → sync-7XFGCRJN.js} +11 -2
- package/dist/sync-7XFGCRJN.js.map +1 -0
- package/package.json +9 -8
- package/dist/chunk-7WKKZ452.js.map +0 -1
- package/dist/chunk-I3L3KNJM.js.map +0 -1
- package/dist/create-ZK2EBXG3.js.map +0 -1
- package/dist/sync-IEH2BVXU.js.map +0 -1
package/dist/bin.js
CHANGED
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
doctor,
|
|
4
|
+
serve
|
|
5
|
+
} from "./chunk-J5HAAQI4.js";
|
|
6
|
+
import {
|
|
7
|
+
init
|
|
8
|
+
} from "./chunk-J2Y3BOVK.js";
|
|
2
9
|
import {
|
|
3
10
|
EXIT,
|
|
4
11
|
NoirCliError,
|
|
5
|
-
doctor,
|
|
6
12
|
fail,
|
|
7
13
|
handleError,
|
|
8
14
|
inferExitCode,
|
|
9
15
|
info,
|
|
10
16
|
isInteractive,
|
|
11
17
|
log,
|
|
12
|
-
serve,
|
|
13
18
|
table,
|
|
14
19
|
warn
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import {
|
|
17
|
-
init
|
|
18
|
-
} from "./chunk-7WKKZ452.js";
|
|
20
|
+
} from "./chunk-OF4OO5W6.js";
|
|
19
21
|
|
|
20
22
|
// src/bin.ts
|
|
21
23
|
import { realpathSync } from "fs";
|
|
22
24
|
import { pathToFileURL } from "url";
|
|
23
|
-
import { SUPPORTED_HOSTS } from "@noir-ai/adapters";
|
|
25
|
+
import { SUPPORTED_HOSTS as SUPPORTED_HOSTS2 } from "@noir-ai/adapters";
|
|
24
26
|
import { NOIR_VERSION as NOIR_VERSION3 } from "@noir-ai/core";
|
|
25
27
|
import { Command, Option } from "commander";
|
|
26
28
|
|
|
@@ -460,15 +462,50 @@ async function daemonRestart(opts) {
|
|
|
460
462
|
}
|
|
461
463
|
|
|
462
464
|
// src/commands/home.ts
|
|
465
|
+
import { SUPPORTED_HOSTS } from "@noir-ai/adapters";
|
|
463
466
|
import { loadProjectInfo as loadProjectInfo3 } from "@noir-ai/core";
|
|
467
|
+
|
|
468
|
+
// src/banner.ts
|
|
469
|
+
import pc from "picocolors";
|
|
470
|
+
var NOIR_BLOCK = [
|
|
471
|
+
"\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 ",
|
|
472
|
+
"\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557",
|
|
473
|
+
"\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551",
|
|
474
|
+
"\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551",
|
|
475
|
+
"\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551",
|
|
476
|
+
"\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D"
|
|
477
|
+
];
|
|
478
|
+
var ROW_COLORS = [pc.magenta, pc.magentaBright, pc.blue, pc.blueBright, pc.cyan, pc.cyanBright];
|
|
479
|
+
var NOIR_TAGLINE = "discipline, context, and memory layer for agentic CLIs";
|
|
480
|
+
function renderBanner(opts = {}) {
|
|
481
|
+
const width = opts.width ?? process.stdout.columns ?? 80;
|
|
482
|
+
const color = opts.color ?? true;
|
|
483
|
+
if (width < 50) {
|
|
484
|
+
return color ? `${pc.magenta("\u25C6")} noir` : "\u25C6 noir";
|
|
485
|
+
}
|
|
486
|
+
return NOIR_BLOCK.map((line, i) => color ? (ROW_COLORS[i] ?? pc.cyan)(line) : line).join("\n");
|
|
487
|
+
}
|
|
488
|
+
function shouldShowBanner(opts) {
|
|
489
|
+
if (opts.quiet === true || opts.json === true) return false;
|
|
490
|
+
const v = process.env.NOIR_NO_BANNER;
|
|
491
|
+
if (v !== void 0 && v !== "") return false;
|
|
492
|
+
return true;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// src/commands/home.ts
|
|
464
496
|
function tryProject() {
|
|
465
497
|
try {
|
|
466
498
|
const info2 = loadProjectInfo3(process.cwd());
|
|
467
|
-
return { id: info2.id, name: info2.name };
|
|
499
|
+
return { id: info2.id, name: info2.name, host: info2.config.host };
|
|
468
500
|
} catch {
|
|
469
501
|
return null;
|
|
470
502
|
}
|
|
471
503
|
}
|
|
504
|
+
var COMMANDS_HINT = "Commands: init \xB7 create \xB7 sync \xB7 status \xB7 context \xB7 memory \xB7 skills \xB7 task \xB7 daemon \xB7 doctor";
|
|
505
|
+
function hostDirection(host) {
|
|
506
|
+
const others = SUPPORTED_HOSTS.filter((h) => h !== host);
|
|
507
|
+
return `\u2192 host: ${host}. Open \`${host}\` to start development \u2014 Noir set the rules, skills, and memory; ${host} runs the code. (other hosts: ${others.join(", ")})`;
|
|
508
|
+
}
|
|
472
509
|
async function home(opts, deps) {
|
|
473
510
|
if (isInteractive(opts)) {
|
|
474
511
|
await runMenu(opts, deps);
|
|
@@ -483,8 +520,20 @@ async function home(opts, deps) {
|
|
|
483
520
|
async function runMenu(opts, deps) {
|
|
484
521
|
const clack = await import("@clack/prompts");
|
|
485
522
|
const project = tryProject();
|
|
486
|
-
|
|
487
|
-
|
|
523
|
+
if (shouldShowBanner(opts)) {
|
|
524
|
+
const host = project?.host ?? "claude";
|
|
525
|
+
process.stderr.write(
|
|
526
|
+
`
|
|
527
|
+
${renderBanner()}
|
|
528
|
+
${NOIR_TAGLINE}
|
|
529
|
+
|
|
530
|
+
${hostDirection(host)}
|
|
531
|
+
${COMMANDS_HINT}
|
|
532
|
+
|
|
533
|
+
`
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
clack.intro(project ? `noir \u2014 ${project.name}` : "noir");
|
|
488
537
|
const choice = await clack.select({
|
|
489
538
|
message: "What would you like to do?",
|
|
490
539
|
initialValue: "status",
|
|
@@ -1240,11 +1289,14 @@ function createProgram() {
|
|
|
1240
1289
|
);
|
|
1241
1290
|
}
|
|
1242
1291
|
}
|
|
1292
|
+
const nonInteractive = opts.json === true || opts.input === false;
|
|
1293
|
+
if (nonInteractive) process.env.NOIR_NON_INTERACTIVE = "1";
|
|
1294
|
+
else delete process.env.NOIR_NON_INTERACTIVE;
|
|
1243
1295
|
});
|
|
1244
1296
|
program2.command("init").description("scaffold Noir in the current project (.noir/, .mcp.json, CLAUDE.md, skills)").option("--transport <transport>", "stdio | streamable-http (default: stdio)", "stdio").option("--url <url>", "streamable-http daemon URL (localhost only)").option(
|
|
1245
1297
|
"--upgrade",
|
|
1246
1298
|
"run scaffold migrations before re-emitting (re-run on an existing project)"
|
|
1247
|
-
).addOption(
|
|
1299
|
+
).option("--force", "re-scaffold even if already initialized (bypasses the already-init no-op)").addOption(
|
|
1248
1300
|
// S10: target host. Defaults to `'claude'` (the regression anchor). The
|
|
1249
1301
|
// chosen host is forwarded to scaffold() + skills emission via
|
|
1250
1302
|
// resolveAdapter. The choice list mirrors `SUPPORTED_HOSTS` so a new host
|
|
@@ -1252,39 +1304,49 @@ function createProgram() {
|
|
|
1252
1304
|
new Option(
|
|
1253
1305
|
"--host <id>",
|
|
1254
1306
|
"target agentic CLI (default: claude) \u2014 drives host-side emission"
|
|
1255
|
-
).choices(
|
|
1307
|
+
).choices(SUPPORTED_HOSTS2)
|
|
1256
1308
|
).action(
|
|
1257
1309
|
async (opts) => {
|
|
1258
1310
|
const transport = opts.transport === "streamable-http" ? "streamable-http" : "stdio";
|
|
1259
1311
|
const upgrade = opts.upgrade === true;
|
|
1312
|
+
const force = opts.force === true;
|
|
1260
1313
|
const host = parseHost(opts.host);
|
|
1261
1314
|
await init(process.cwd(), {
|
|
1262
1315
|
transport,
|
|
1263
1316
|
url: opts.url,
|
|
1264
1317
|
...upgrade ? { upgrade } : {},
|
|
1318
|
+
...force ? { force } : {},
|
|
1265
1319
|
...host !== void 0 ? { host } : {}
|
|
1266
1320
|
});
|
|
1267
1321
|
}
|
|
1268
1322
|
);
|
|
1269
|
-
program2.command("create [dir]").description("bootstrap the Noir AI layer in a new or empty directory").option("--transport <transport>", "stdio | streamable-http (default: stdio)", "stdio").option("--url <url>", "streamable-http daemon URL (localhost only)").addOption(
|
|
1323
|
+
program2.command("create [dir]").description("bootstrap the Noir AI layer in a new or empty directory").option("--transport <transport>", "stdio | streamable-http (default: stdio)", "stdio").option("--url <url>", "streamable-http daemon URL (localhost only)").option("--force", "re-scaffold even if already initialized (bypasses the already-init no-op)").addOption(
|
|
1270
1324
|
new Option(
|
|
1271
1325
|
"--host <id>",
|
|
1272
1326
|
"target agentic CLI (default: claude) \u2014 drives host-side emission"
|
|
1273
|
-
).choices(
|
|
1327
|
+
).choices(SUPPORTED_HOSTS2)
|
|
1274
1328
|
).action(
|
|
1275
1329
|
async (dir, opts) => {
|
|
1276
1330
|
const transport = opts.transport === "streamable-http" ? "streamable-http" : "stdio";
|
|
1331
|
+
const force = opts.force === true;
|
|
1277
1332
|
const host = parseHost(opts.host);
|
|
1278
|
-
const { create } = await import("./create-
|
|
1333
|
+
const { create } = await import("./create-VK7JX6IB.js");
|
|
1279
1334
|
await create(dir, {
|
|
1280
1335
|
transport,
|
|
1281
1336
|
url: opts.url,
|
|
1337
|
+
...force ? { force } : {},
|
|
1282
1338
|
...host !== void 0 ? { host } : {}
|
|
1283
1339
|
});
|
|
1284
1340
|
}
|
|
1285
1341
|
);
|
|
1286
1342
|
program2.command("sync").description(
|
|
1287
1343
|
"re-emit Noir managed files (.mcp.json, CLAUDE.md blocks, NOIR.md brief, ignores) + skills"
|
|
1344
|
+
).option(
|
|
1345
|
+
"--force",
|
|
1346
|
+
"overwrite differing regenerated files without prompting (bypasses the conflict menu)"
|
|
1347
|
+
).option(
|
|
1348
|
+
"--merge",
|
|
1349
|
+
"three-way merge managed regions (preserve hand-edits inside <!-- noir:* --> markers)"
|
|
1288
1350
|
).addOption(
|
|
1289
1351
|
// S10: optional `--host` override. When omitted, sync reads host from
|
|
1290
1352
|
// `.noir/config.yml` (whatever `noir init --host <id>` persisted). The
|
|
@@ -1292,14 +1354,20 @@ function createProgram() {
|
|
|
1292
1354
|
new Option(
|
|
1293
1355
|
"--host <id>",
|
|
1294
1356
|
"override the configured host (advanced; default reads .noir/config.yml)"
|
|
1295
|
-
).choices(
|
|
1357
|
+
).choices(SUPPORTED_HOSTS2)
|
|
1296
1358
|
).action(async (opts) => {
|
|
1297
|
-
const { sync } = await import("./sync-
|
|
1359
|
+
const { sync } = await import("./sync-7XFGCRJN.js");
|
|
1298
1360
|
const host = parseHost(opts.host);
|
|
1299
|
-
|
|
1361
|
+
const force = opts.force === true;
|
|
1362
|
+
const merge = opts.merge === true;
|
|
1363
|
+
if (host === void 0 && !force && !merge) {
|
|
1300
1364
|
await sync(process.cwd());
|
|
1301
1365
|
} else {
|
|
1302
|
-
await sync(process.cwd(), {
|
|
1366
|
+
await sync(process.cwd(), {
|
|
1367
|
+
...host !== void 0 ? { host } : {},
|
|
1368
|
+
...force ? { force } : {},
|
|
1369
|
+
...merge ? { merge } : {}
|
|
1370
|
+
});
|
|
1303
1371
|
}
|
|
1304
1372
|
});
|
|
1305
1373
|
const mcpCmd = program2.command("mcp").description("MCP server control");
|
|
@@ -1328,8 +1396,13 @@ function createProgram() {
|
|
|
1328
1396
|
daemonGrp.action(() => {
|
|
1329
1397
|
throw new NoirCliError(EXIT.USAGE, "Usage: noir daemon start|stop|status|restart");
|
|
1330
1398
|
});
|
|
1331
|
-
program2.command("doctor").description("environment + project health").
|
|
1332
|
-
|
|
1399
|
+
program2.command("doctor").description("environment + project health").option(
|
|
1400
|
+
"--dedup",
|
|
1401
|
+
"scan host-context + .noir/ docs for semantic near-duplicates (loads the local embedder)"
|
|
1402
|
+
).action(async (...args) => {
|
|
1403
|
+
const g = actionGlobals(args);
|
|
1404
|
+
const dedup = trailingCmd(args).opts().dedup === true;
|
|
1405
|
+
await doctor({ ...toCliOptions(g), ...dedup ? { dedup: true } : {} });
|
|
1333
1406
|
});
|
|
1334
1407
|
program2.command("status").description("project + daemon + workflow + store snapshot").action(async (...args) => {
|
|
1335
1408
|
await status(toStatusOptions(actionGlobals(args)));
|