@noir-ai/cli 1.17.0-beta.1 → 1.18.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 +89 -27
- package/dist/bin.js.map +1 -1
- package/dist/hygiene-scan.js +10 -1
- package/dist/hygiene-scan.js.map +1 -1
- package/dist/index.js +123 -61
- package/dist/index.js.map +1 -1
- package/dist/tui/{chunk-NZMM6YXE.js → chunk-A5XEQWRN.js} +82 -26
- package/dist/tui/chunk-A5XEQWRN.js.map +1 -0
- package/dist/tui/{create-4XGNRRP7.js → create-GUXMIKZB.js} +2 -2
- package/dist/tui/index.js +1 -1
- package/dist/tui/{sync-Q3KXM5RQ.js → sync-PXMB4SJT.js} +2 -2
- package/package.json +11 -11
- package/dist/tui/chunk-NZMM6YXE.js.map +0 -1
- /package/dist/tui/{create-4XGNRRP7.js.map → create-GUXMIKZB.js.map} +0 -0
- /package/dist/tui/{sync-Q3KXM5RQ.js.map → sync-PXMB4SJT.js.map} +0 -0
|
@@ -1135,6 +1135,14 @@ var HYGIENE_MARKDOWN_EXTENSIONS = /\.(?:md|mdx)$/i;
|
|
|
1135
1135
|
var HYGIENE_SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", "dist", "coverage"]);
|
|
1136
1136
|
var HYGIENE_EXCLUDED_DIRS = /* @__PURE__ */ new Set(["docs/internal", "docs/decisions", "docs/roadmap"]);
|
|
1137
1137
|
var HYGIENE_EXCLUDED_FILES = /* @__PURE__ */ new Set(["CHANGELOG.md"]);
|
|
1138
|
+
var HYGIENE_EXCLUDED_PATHS = /* @__PURE__ */ new Set([
|
|
1139
|
+
"docs/README.md",
|
|
1140
|
+
"docs/reference/cli.md",
|
|
1141
|
+
"docs/reference/config.md",
|
|
1142
|
+
"docs/reference/mcp-tools.md",
|
|
1143
|
+
"docs/reference/packages.md",
|
|
1144
|
+
"docs/reference/skills.md"
|
|
1145
|
+
]);
|
|
1138
1146
|
function readDirEntries(dir) {
|
|
1139
1147
|
try {
|
|
1140
1148
|
return readdirSync2(dir, { withFileTypes: true });
|
|
@@ -1165,7 +1173,8 @@ function hasScannableLayout(root) {
|
|
|
1165
1173
|
}
|
|
1166
1174
|
function addHygieneFile(rel, walk) {
|
|
1167
1175
|
const name = rel.slice(rel.lastIndexOf("/") + 1);
|
|
1168
|
-
if (name.startsWith(".") || HYGIENE_EXCLUDED_FILES.has(name))
|
|
1176
|
+
if (name.startsWith(".") || HYGIENE_EXCLUDED_FILES.has(name) || HYGIENE_EXCLUDED_PATHS.has(rel))
|
|
1177
|
+
return;
|
|
1169
1178
|
const kind = hygieneKindOf(rel);
|
|
1170
1179
|
if (kind === null) return;
|
|
1171
1180
|
if (walk.files.length >= HYGIENE_MAX_FILES) {
|
|
@@ -2921,11 +2930,13 @@ function requiredArgLabel(cmd) {
|
|
|
2921
2930
|
const required = cmd.registeredArguments.find((arg) => arg.required);
|
|
2922
2931
|
return required?.name();
|
|
2923
2932
|
}
|
|
2933
|
+
var INTERNAL_LEAF_COMMANDS = /* @__PURE__ */ new Set(["hook"]);
|
|
2924
2934
|
function collectLeaves(cmd, path, out) {
|
|
2925
2935
|
const children = cmd.commands;
|
|
2926
2936
|
const isLeaf = hasAction(cmd) && children.length === 0;
|
|
2927
2937
|
if (isLeaf) {
|
|
2928
2938
|
const argv = path;
|
|
2939
|
+
if (INTERNAL_LEAF_COMMANDS.has(argv.join(" "))) return;
|
|
2929
2940
|
const id = argv.join(" ");
|
|
2930
2941
|
const description = cmd.description() || argv.join(" ");
|
|
2931
2942
|
out.push({
|
|
@@ -3379,8 +3390,50 @@ ${COMMANDS_HINT}
|
|
|
3379
3390
|
await runGroupedMenu(clack, opts, deps, sections);
|
|
3380
3391
|
}
|
|
3381
3392
|
|
|
3393
|
+
// src/commands/hook.ts
|
|
3394
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
|
|
3395
|
+
import { join as join4 } from "path";
|
|
3396
|
+
function hook() {
|
|
3397
|
+
let eventName = "SessionStart";
|
|
3398
|
+
let root = process.cwd();
|
|
3399
|
+
try {
|
|
3400
|
+
const input = JSON.parse(readFileSync4(0, "utf8"));
|
|
3401
|
+
if (typeof input.hook_event_name === "string" && input.hook_event_name !== "") {
|
|
3402
|
+
eventName = input.hook_event_name;
|
|
3403
|
+
}
|
|
3404
|
+
if (typeof input.cwd === "string" && input.cwd !== "") root = input.cwd;
|
|
3405
|
+
} catch {
|
|
3406
|
+
}
|
|
3407
|
+
process.stdout.write(JSON.stringify(hookOutput(eventName, root)));
|
|
3408
|
+
}
|
|
3409
|
+
function hookOutput(eventName, root) {
|
|
3410
|
+
let routerPath = null;
|
|
3411
|
+
let rulesPath = null;
|
|
3412
|
+
for (let dir = root; ; dir = join4(dir, "..")) {
|
|
3413
|
+
const router = join4(dir, ".noir", "router.md");
|
|
3414
|
+
const rules = join4(dir, ".noir", "rules", "anti-slop.md");
|
|
3415
|
+
if (existsSync3(router) || existsSync3(rules)) {
|
|
3416
|
+
routerPath = router;
|
|
3417
|
+
rulesPath = rules;
|
|
3418
|
+
break;
|
|
3419
|
+
}
|
|
3420
|
+
const parent = join4(dir, "..");
|
|
3421
|
+
if (parent === dir) break;
|
|
3422
|
+
}
|
|
3423
|
+
const parts = [];
|
|
3424
|
+
for (const path of [routerPath, rulesPath]) {
|
|
3425
|
+
if (path === null) continue;
|
|
3426
|
+
try {
|
|
3427
|
+
const text = readFileSync4(path, "utf8").trim();
|
|
3428
|
+
if (text !== "") parts.push(text);
|
|
3429
|
+
} catch {
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
return parts.length === 0 ? { hookSpecificOutput: { hookEventName: eventName } } : { hookSpecificOutput: { hookEventName: eventName, additionalContext: parts.join("\n\n") } };
|
|
3433
|
+
}
|
|
3434
|
+
|
|
3382
3435
|
// src/commands/memory.ts
|
|
3383
|
-
import { readFileSync as
|
|
3436
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
3384
3437
|
import { loadProjectInfo as loadProjectInfo9 } from "@noir-ai/core";
|
|
3385
3438
|
function resolveWorkspace() {
|
|
3386
3439
|
const routing = workspaceRoutingTarget(process.cwd());
|
|
@@ -3598,14 +3651,14 @@ async function resolveCaptureContent(opts) {
|
|
|
3598
3651
|
if (typeof opts.content === "string" && opts.content.length > 0) return opts.content;
|
|
3599
3652
|
if (typeof opts.file === "string" && opts.file.length > 0) {
|
|
3600
3653
|
try {
|
|
3601
|
-
return
|
|
3654
|
+
return readFileSync5(opts.file, "utf8");
|
|
3602
3655
|
} catch {
|
|
3603
3656
|
fail(EXIT.USAGE, `memory capture could not read --file ${opts.file}`, opts);
|
|
3604
3657
|
}
|
|
3605
3658
|
}
|
|
3606
3659
|
if (!process.stdin.isTTY) {
|
|
3607
3660
|
try {
|
|
3608
|
-
return
|
|
3661
|
+
return readFileSync5(0, "utf8");
|
|
3609
3662
|
} catch {
|
|
3610
3663
|
fail(
|
|
3611
3664
|
EXIT.USAGE,
|
|
@@ -3885,8 +3938,8 @@ async function release(opts) {
|
|
|
3885
3938
|
}
|
|
3886
3939
|
|
|
3887
3940
|
// src/commands/run.ts
|
|
3888
|
-
import { existsSync as
|
|
3889
|
-
import { join as
|
|
3941
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
3942
|
+
import { join as join5 } from "path";
|
|
3890
3943
|
import { SUPPORTED_HOSTS } from "@noir-ai/adapters";
|
|
3891
3944
|
import { isDeniedEnvKey as isDeniedEnvKey2, loadNoirEnv as loadNoirEnv3, NOIR_DIR as NOIR_DIR2, parseConfig, paths as paths2 } from "@noir-ai/core";
|
|
3892
3945
|
|
|
@@ -4991,7 +5044,7 @@ async function runOnce(prompt, opts, resumeSessionId) {
|
|
|
4991
5044
|
const customBinary = opts.command ?? profile.binary;
|
|
4992
5045
|
const extraArgs = resumeSessionId === void 0 ? profile.args : [...profile.args ?? [], "--resume", resumeSessionId];
|
|
4993
5046
|
const env2 = profile.env ? mergeEnv(process.env, profile.env) : void 0;
|
|
4994
|
-
if (!
|
|
5047
|
+
if (!existsSync4(join5(root, NOIR_DIR2, ".env"))) {
|
|
4995
5048
|
log(
|
|
4996
5049
|
`This project has no ${NOIR_DIR2}/.env \u2014 that is where Noir reads project credentials and run config from. Run \`noir init\` to scaffold one (\`noir run\` works without it).`,
|
|
4997
5050
|
opts
|
|
@@ -5154,7 +5207,7 @@ function safeTranscript(host, lines) {
|
|
|
5154
5207
|
function writeTranscript(host, lines, root = process.cwd()) {
|
|
5155
5208
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
5156
5209
|
const dir = paths2.transcriptsDir(root);
|
|
5157
|
-
const file =
|
|
5210
|
+
const file = join5(dir, `${host}-${ts}.jsonl`);
|
|
5158
5211
|
try {
|
|
5159
5212
|
mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
5160
5213
|
writeFileSync4(file, `${lines.join("\n")}${lines.length > 0 ? "\n" : ""}`, { mode: 384 });
|
|
@@ -5175,7 +5228,7 @@ import {
|
|
|
5175
5228
|
} from "@noir-ai/skills";
|
|
5176
5229
|
|
|
5177
5230
|
// src/init.ts
|
|
5178
|
-
import { existsSync as
|
|
5231
|
+
import { existsSync as existsSync5 } from "fs";
|
|
5179
5232
|
import { resolveAdapter as resolveAdapter3 } from "@noir-ai/adapters";
|
|
5180
5233
|
import { loadProjectInfo as loadProjectInfo11, paths as paths3 } from "@noir-ai/core";
|
|
5181
5234
|
import { scaffold } from "@noir-ai/create";
|
|
@@ -5285,8 +5338,8 @@ function labelFor(resolution) {
|
|
|
5285
5338
|
}
|
|
5286
5339
|
|
|
5287
5340
|
// src/dedup-write.ts
|
|
5288
|
-
import { mkdirSync as mkdirSync3, readFileSync as
|
|
5289
|
-
import { join as
|
|
5341
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync6, rmSync, writeFileSync as writeFileSync5 } from "fs";
|
|
5342
|
+
import { join as join6 } from "path";
|
|
5290
5343
|
import { sha256Hex as sha256Hex2, sha256Hex12 } from "@noir-ai/core";
|
|
5291
5344
|
var HOST_CONTEXT_RELS = /* @__PURE__ */ new Set(["CLAUDE.md", "AGENTS.md", "GEMINI.md", ".noir/rules/RULES.md"]);
|
|
5292
5345
|
var ACTION_THRESHOLD = 0.95;
|
|
@@ -5302,10 +5355,10 @@ async function checkWritePathDedup(root, res, opts) {
|
|
|
5302
5355
|
if (embed === void 0) return result;
|
|
5303
5356
|
const cachedEmbed = makeCachedEmbed(cache, embed);
|
|
5304
5357
|
for (const proposedRel of writtenHostFiles) {
|
|
5305
|
-
const proposedAbs =
|
|
5358
|
+
const proposedAbs = join6(root, proposedRel);
|
|
5306
5359
|
let proposedText;
|
|
5307
5360
|
try {
|
|
5308
|
-
proposedText =
|
|
5361
|
+
proposedText = readFileSync6(proposedAbs, "utf8");
|
|
5309
5362
|
} catch {
|
|
5310
5363
|
continue;
|
|
5311
5364
|
}
|
|
@@ -5349,7 +5402,7 @@ async function checkWritePathDedup(root, res, opts) {
|
|
|
5349
5402
|
`
|
|
5350
5403
|
);
|
|
5351
5404
|
}
|
|
5352
|
-
const matchedText = safeRead(
|
|
5405
|
+
const matchedText = safeRead(join6(root, matchedRel));
|
|
5353
5406
|
result.conflicts.push({
|
|
5354
5407
|
path: proposedRel,
|
|
5355
5408
|
mode: "artifact",
|
|
@@ -5433,21 +5486,21 @@ async function promptDedupAction(root, proposedRel, matchedRel, proposedText, si
|
|
|
5433
5486
|
if (clack.isCancel(choice)) return "preserve";
|
|
5434
5487
|
if (choice === "skip") {
|
|
5435
5488
|
try {
|
|
5436
|
-
rmSync(
|
|
5489
|
+
rmSync(join6(root, proposedRel), { force: true });
|
|
5437
5490
|
} catch {
|
|
5438
5491
|
}
|
|
5439
5492
|
return "preserve";
|
|
5440
5493
|
} else if (choice === "replace") {
|
|
5441
5494
|
try {
|
|
5442
|
-
writeFileSync5(
|
|
5495
|
+
writeFileSync5(join6(root, matchedRel), proposedText, "utf8");
|
|
5443
5496
|
} catch {
|
|
5444
5497
|
}
|
|
5445
5498
|
return "replace";
|
|
5446
5499
|
} else if (choice === "mirror") {
|
|
5447
5500
|
try {
|
|
5448
|
-
const existing =
|
|
5501
|
+
const existing = readFileSync6(join6(root, matchedRel), "utf8");
|
|
5449
5502
|
writeFileSync5(
|
|
5450
|
-
|
|
5503
|
+
join6(root, matchedRel),
|
|
5451
5504
|
`${existing}
|
|
5452
5505
|
|
|
5453
5506
|
<!-- mirrored from ${proposedRel} -->
|
|
@@ -5465,11 +5518,11 @@ function emptyCache() {
|
|
|
5465
5518
|
return { version: DEDUP_CACHE_VERSION, model: "", entries: {} };
|
|
5466
5519
|
}
|
|
5467
5520
|
function cachePath(root) {
|
|
5468
|
-
return
|
|
5521
|
+
return join6(root, ".noir", "dedup-cache.json");
|
|
5469
5522
|
}
|
|
5470
5523
|
function loadCache(root) {
|
|
5471
5524
|
try {
|
|
5472
|
-
const raw =
|
|
5525
|
+
const raw = readFileSync6(cachePath(root), "utf8");
|
|
5473
5526
|
const parsed = JSON.parse(raw);
|
|
5474
5527
|
if (parsed.version !== DEDUP_CACHE_VERSION) return emptyCache();
|
|
5475
5528
|
if (typeof parsed.entries !== "object" || parsed.entries === null) return emptyCache();
|
|
@@ -5484,7 +5537,7 @@ function loadCache(root) {
|
|
|
5484
5537
|
}
|
|
5485
5538
|
function saveCache(root, cache) {
|
|
5486
5539
|
try {
|
|
5487
|
-
mkdirSync3(
|
|
5540
|
+
mkdirSync3(join6(root, ".noir"), { recursive: true });
|
|
5488
5541
|
writeFileSync5(cachePath(root), JSON.stringify(cache), "utf8");
|
|
5489
5542
|
} catch {
|
|
5490
5543
|
}
|
|
@@ -5501,7 +5554,7 @@ function makeCachedEmbed(cache, embed) {
|
|
|
5501
5554
|
}
|
|
5502
5555
|
function safeRead(abs) {
|
|
5503
5556
|
try {
|
|
5504
|
-
return
|
|
5557
|
+
return readFileSync6(abs, "utf8");
|
|
5505
5558
|
} catch {
|
|
5506
5559
|
return void 0;
|
|
5507
5560
|
}
|
|
@@ -5584,7 +5637,7 @@ async function init(root, opts) {
|
|
|
5584
5637
|
}
|
|
5585
5638
|
function resolveInitHost(root, opts) {
|
|
5586
5639
|
if (opts.host !== void 0) return opts.host;
|
|
5587
|
-
if (!
|
|
5640
|
+
if (!existsSync5(paths3.config(root))) return "claude";
|
|
5588
5641
|
try {
|
|
5589
5642
|
return loadProjectInfo11(root).config.host;
|
|
5590
5643
|
} catch {
|
|
@@ -6092,7 +6145,7 @@ function createProgram() {
|
|
|
6092
6145
|
const force = opts.force === true;
|
|
6093
6146
|
const host = parseHost(opts.host);
|
|
6094
6147
|
const dryRun = opts.dryRun === true || opts.preview === true;
|
|
6095
|
-
const { create } = await import("./create-
|
|
6148
|
+
const { create } = await import("./create-GUXMIKZB.js");
|
|
6096
6149
|
const result = await create(dir, {
|
|
6097
6150
|
transport,
|
|
6098
6151
|
url: opts.url,
|
|
@@ -6131,7 +6184,7 @@ function createProgram() {
|
|
|
6131
6184
|
).choices(SUPPORTED_HOSTS2)
|
|
6132
6185
|
).action(
|
|
6133
6186
|
async (opts, cmd) => {
|
|
6134
|
-
const { sync } = await import("./sync-
|
|
6187
|
+
const { sync } = await import("./sync-PXMB4SJT.js");
|
|
6135
6188
|
const host = parseHost(opts.host);
|
|
6136
6189
|
const force = opts.force === true;
|
|
6137
6190
|
const merge = opts.merge === true;
|
|
@@ -6278,6 +6331,9 @@ function createProgram() {
|
|
|
6278
6331
|
program2.command("env").description("which configuration is in effect and where each value comes from").action(async (...args) => {
|
|
6279
6332
|
await env(toCliOptions(actionGlobals(args)));
|
|
6280
6333
|
});
|
|
6334
|
+
program2.command("hook", { hidden: true }).description("host hook runner (SessionStart / SubagentStart context injection)").action(async () => {
|
|
6335
|
+
await hook();
|
|
6336
|
+
});
|
|
6281
6337
|
const contextGrp = program2.command("context").description("context engine");
|
|
6282
6338
|
contextGrp.command("search").description("hybrid search over the indexed context").argument("<query>", "search query").option("--limit <n>", "max results", "10").action(async (...args) => {
|
|
6283
6339
|
const cmd = trailingCmd(args);
|
|
@@ -7257,4 +7313,4 @@ export {
|
|
|
7257
7313
|
assertTransportUrl,
|
|
7258
7314
|
buildPaletteCommandsForTui
|
|
7259
7315
|
};
|
|
7260
|
-
//# sourceMappingURL=chunk-
|
|
7316
|
+
//# sourceMappingURL=chunk-A5XEQWRN.js.map
|