@noir-ai/cli 1.2.0-beta.1 → 1.3.0-beta.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/bin.js +97 -22
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-UGUQQSWH.js → chunk-E5XVH7QR.js} +10 -2
- package/dist/chunk-E5XVH7QR.js.map +1 -0
- package/dist/{chunk-OMUB7XOA.js → chunk-J5HAAQI4.js} +93 -149
- 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-WP5ZKMCW.js → create-2P3T7UGZ.js} +9 -3
- package/dist/create-2P3T7UGZ.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-OMUB7XOA.js.map +0 -1
- package/dist/chunk-UGUQQSWH.js.map +0 -1
- package/dist/create-WP5ZKMCW.js.map +0 -1
- package/dist/sync-IEH2BVXU.js.map +0 -1
package/dist/bin.js
CHANGED
|
@@ -1,25 +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-E5XVH7QR.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-UGUQQSWH.js";
|
|
20
|
+
} from "./chunk-OF4OO5W6.js";
|
|
19
21
|
|
|
20
22
|
// src/bin.ts
|
|
23
|
+
import { realpathSync } from "fs";
|
|
21
24
|
import { pathToFileURL } from "url";
|
|
22
|
-
import { SUPPORTED_HOSTS } from "@noir-ai/adapters";
|
|
25
|
+
import { SUPPORTED_HOSTS as SUPPORTED_HOSTS2 } from "@noir-ai/adapters";
|
|
23
26
|
import { NOIR_VERSION as NOIR_VERSION3 } from "@noir-ai/core";
|
|
24
27
|
import { Command, Option } from "commander";
|
|
25
28
|
|
|
@@ -459,15 +462,50 @@ async function daemonRestart(opts) {
|
|
|
459
462
|
}
|
|
460
463
|
|
|
461
464
|
// src/commands/home.ts
|
|
465
|
+
import { SUPPORTED_HOSTS } from "@noir-ai/adapters";
|
|
462
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
|
|
463
496
|
function tryProject() {
|
|
464
497
|
try {
|
|
465
498
|
const info2 = loadProjectInfo3(process.cwd());
|
|
466
|
-
return { id: info2.id, name: info2.name };
|
|
499
|
+
return { id: info2.id, name: info2.name, host: info2.config.host };
|
|
467
500
|
} catch {
|
|
468
501
|
return null;
|
|
469
502
|
}
|
|
470
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
|
+
}
|
|
471
509
|
async function home(opts, deps) {
|
|
472
510
|
if (isInteractive(opts)) {
|
|
473
511
|
await runMenu(opts, deps);
|
|
@@ -482,8 +520,20 @@ async function home(opts, deps) {
|
|
|
482
520
|
async function runMenu(opts, deps) {
|
|
483
521
|
const clack = await import("@clack/prompts");
|
|
484
522
|
const project = tryProject();
|
|
485
|
-
|
|
486
|
-
|
|
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");
|
|
487
537
|
const choice = await clack.select({
|
|
488
538
|
message: "What would you like to do?",
|
|
489
539
|
initialValue: "status",
|
|
@@ -1239,11 +1289,14 @@ function createProgram() {
|
|
|
1239
1289
|
);
|
|
1240
1290
|
}
|
|
1241
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;
|
|
1242
1295
|
});
|
|
1243
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(
|
|
1244
1297
|
"--upgrade",
|
|
1245
1298
|
"run scaffold migrations before re-emitting (re-run on an existing project)"
|
|
1246
|
-
).addOption(
|
|
1299
|
+
).option("--force", "re-scaffold even if already initialized (bypasses the already-init no-op)").addOption(
|
|
1247
1300
|
// S10: target host. Defaults to `'claude'` (the regression anchor). The
|
|
1248
1301
|
// chosen host is forwarded to scaffold() + skills emission via
|
|
1249
1302
|
// resolveAdapter. The choice list mirrors `SUPPORTED_HOSTS` so a new host
|
|
@@ -1251,39 +1304,49 @@ function createProgram() {
|
|
|
1251
1304
|
new Option(
|
|
1252
1305
|
"--host <id>",
|
|
1253
1306
|
"target agentic CLI (default: claude) \u2014 drives host-side emission"
|
|
1254
|
-
).choices(
|
|
1307
|
+
).choices(SUPPORTED_HOSTS2)
|
|
1255
1308
|
).action(
|
|
1256
1309
|
async (opts) => {
|
|
1257
1310
|
const transport = opts.transport === "streamable-http" ? "streamable-http" : "stdio";
|
|
1258
1311
|
const upgrade = opts.upgrade === true;
|
|
1312
|
+
const force = opts.force === true;
|
|
1259
1313
|
const host = parseHost(opts.host);
|
|
1260
1314
|
await init(process.cwd(), {
|
|
1261
1315
|
transport,
|
|
1262
1316
|
url: opts.url,
|
|
1263
1317
|
...upgrade ? { upgrade } : {},
|
|
1318
|
+
...force ? { force } : {},
|
|
1264
1319
|
...host !== void 0 ? { host } : {}
|
|
1265
1320
|
});
|
|
1266
1321
|
}
|
|
1267
1322
|
);
|
|
1268
|
-
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(
|
|
1269
1324
|
new Option(
|
|
1270
1325
|
"--host <id>",
|
|
1271
1326
|
"target agentic CLI (default: claude) \u2014 drives host-side emission"
|
|
1272
|
-
).choices(
|
|
1327
|
+
).choices(SUPPORTED_HOSTS2)
|
|
1273
1328
|
).action(
|
|
1274
1329
|
async (dir, opts) => {
|
|
1275
1330
|
const transport = opts.transport === "streamable-http" ? "streamable-http" : "stdio";
|
|
1331
|
+
const force = opts.force === true;
|
|
1276
1332
|
const host = parseHost(opts.host);
|
|
1277
|
-
const { create } = await import("./create-
|
|
1333
|
+
const { create } = await import("./create-2P3T7UGZ.js");
|
|
1278
1334
|
await create(dir, {
|
|
1279
1335
|
transport,
|
|
1280
1336
|
url: opts.url,
|
|
1337
|
+
...force ? { force } : {},
|
|
1281
1338
|
...host !== void 0 ? { host } : {}
|
|
1282
1339
|
});
|
|
1283
1340
|
}
|
|
1284
1341
|
);
|
|
1285
1342
|
program2.command("sync").description(
|
|
1286
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)"
|
|
1287
1350
|
).addOption(
|
|
1288
1351
|
// S10: optional `--host` override. When omitted, sync reads host from
|
|
1289
1352
|
// `.noir/config.yml` (whatever `noir init --host <id>` persisted). The
|
|
@@ -1291,14 +1354,20 @@ function createProgram() {
|
|
|
1291
1354
|
new Option(
|
|
1292
1355
|
"--host <id>",
|
|
1293
1356
|
"override the configured host (advanced; default reads .noir/config.yml)"
|
|
1294
|
-
).choices(
|
|
1357
|
+
).choices(SUPPORTED_HOSTS2)
|
|
1295
1358
|
).action(async (opts) => {
|
|
1296
|
-
const { sync } = await import("./sync-
|
|
1359
|
+
const { sync } = await import("./sync-7XFGCRJN.js");
|
|
1297
1360
|
const host = parseHost(opts.host);
|
|
1298
|
-
|
|
1361
|
+
const force = opts.force === true;
|
|
1362
|
+
const merge = opts.merge === true;
|
|
1363
|
+
if (host === void 0 && !force && !merge) {
|
|
1299
1364
|
await sync(process.cwd());
|
|
1300
1365
|
} else {
|
|
1301
|
-
await sync(process.cwd(), {
|
|
1366
|
+
await sync(process.cwd(), {
|
|
1367
|
+
...host !== void 0 ? { host } : {},
|
|
1368
|
+
...force ? { force } : {},
|
|
1369
|
+
...merge ? { merge } : {}
|
|
1370
|
+
});
|
|
1302
1371
|
}
|
|
1303
1372
|
});
|
|
1304
1373
|
const mcpCmd = program2.command("mcp").description("MCP server control");
|
|
@@ -1327,8 +1396,13 @@ function createProgram() {
|
|
|
1327
1396
|
daemonGrp.action(() => {
|
|
1328
1397
|
throw new NoirCliError(EXIT.USAGE, "Usage: noir daemon start|stop|status|restart");
|
|
1329
1398
|
});
|
|
1330
|
-
program2.command("doctor").description("environment + project health").
|
|
1331
|
-
|
|
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 } : {} });
|
|
1332
1406
|
});
|
|
1333
1407
|
program2.command("status").description("project + daemon + workflow + store snapshot").action(async (...args) => {
|
|
1334
1408
|
await status(toStatusOptions(actionGlobals(args)));
|
|
@@ -1507,7 +1581,8 @@ async function run(argv = []) {
|
|
|
1507
1581
|
var isMainModule = (() => {
|
|
1508
1582
|
try {
|
|
1509
1583
|
const entry = process.argv[1];
|
|
1510
|
-
|
|
1584
|
+
if (typeof entry !== "string" || entry.length === 0) return false;
|
|
1585
|
+
return pathToFileURL(realpathSync(entry)).href === import.meta.url;
|
|
1511
1586
|
} catch {
|
|
1512
1587
|
return false;
|
|
1513
1588
|
}
|