@earntori/cli 0.2.16 → 0.2.17
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 +79 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -305,11 +305,51 @@ function projectId() {
|
|
|
305
305
|
catch { }
|
|
306
306
|
return "local:" + createHash("sha256").update(process.cwd()).digest("hex").slice(0, 12);
|
|
307
307
|
}
|
|
308
|
+
/** Spec rev 86: paths never sent to Tori. `ignore` in .tori/project.json is a list of glob patterns
|
|
309
|
+
* (`fixtures/`, `seeds/**`, `*.snap`, `scratch`). A pattern with no slash matches at any depth. */
|
|
310
|
+
function ignorePatterns(root) {
|
|
311
|
+
try {
|
|
312
|
+
const j = JSON.parse(readFileSync(join(root, ".tori", "project.json"), "utf8"));
|
|
313
|
+
return Array.isArray(j?.ignore) ? j.ignore.filter((x) => typeof x === "string") : [];
|
|
314
|
+
}
|
|
315
|
+
catch {
|
|
316
|
+
return [];
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
function globToRe(g) {
|
|
320
|
+
let p = g.trim().replace(/^\.\//, "").replace(/\/+$/, "");
|
|
321
|
+
let re = "";
|
|
322
|
+
for (let i = 0; i < p.length; i++) {
|
|
323
|
+
const c = p[i];
|
|
324
|
+
if (c === "*") {
|
|
325
|
+
if (p[i + 1] === "*") {
|
|
326
|
+
re += ".*";
|
|
327
|
+
i++;
|
|
328
|
+
if (p[i + 1] === "/")
|
|
329
|
+
i++;
|
|
330
|
+
}
|
|
331
|
+
else
|
|
332
|
+
re += "[^/]*";
|
|
333
|
+
}
|
|
334
|
+
else if (c === "?")
|
|
335
|
+
re += "[^/]";
|
|
336
|
+
else
|
|
337
|
+
re += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
338
|
+
}
|
|
339
|
+
return new RegExp((p.includes("/") ? "^" : "(^|/)") + re + "(/|$)");
|
|
340
|
+
}
|
|
341
|
+
function isIgnored(rel, pats) {
|
|
342
|
+
if (!pats.length)
|
|
343
|
+
return false;
|
|
344
|
+
const r = rel.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
345
|
+
return pats.some((g) => globToRe(g).test(r));
|
|
346
|
+
}
|
|
308
347
|
function gitChanged() {
|
|
309
348
|
try {
|
|
310
349
|
const o = execSync("git status --porcelain --untracked-files=all", { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
311
350
|
const SKIP = /(^|\/)(node_modules|dist|build|out|\.next|\.git|coverage|vendor|\.venv|venv|__pycache__|\.turbo|\.cache)(\/|$)/;
|
|
312
|
-
|
|
351
|
+
const pats = ignorePatterns(process.cwd());
|
|
352
|
+
return o.split("\n").map((l) => l.slice(3).trim()).filter(Boolean).map((p) => (p.includes(" -> ") ? p.split(" -> ")[1] : p)).filter((p) => !SKIP.test(p) && !isIgnored(p, pats)).slice(0, 200);
|
|
313
353
|
}
|
|
314
354
|
catch {
|
|
315
355
|
return [];
|
|
@@ -317,10 +357,11 @@ function gitChanged() {
|
|
|
317
357
|
}
|
|
318
358
|
function readCode(paths) {
|
|
319
359
|
const files = [];
|
|
360
|
+
const pats = ignorePatterns(process.cwd());
|
|
320
361
|
for (const p of paths) {
|
|
321
362
|
const abs = isAbsolute(p) ? p : resolve(p);
|
|
322
363
|
const rel = relative(process.cwd(), abs);
|
|
323
|
-
if (rel.startsWith("..") || rel.includes("node_modules/") || !CODE_EXT.test(rel) || !existsSync(abs))
|
|
364
|
+
if (rel.startsWith("..") || rel.includes("node_modules/") || !CODE_EXT.test(rel) || !existsSync(abs) || isIgnored(rel, pats))
|
|
324
365
|
continue;
|
|
325
366
|
try {
|
|
326
367
|
const c = readFileSync(abs, "utf8");
|
|
@@ -593,13 +634,48 @@ function logout() {
|
|
|
593
634
|
unlinkSync(join(SESSIONS_DIR, f));
|
|
594
635
|
out({ ok: true }, "\u2713 Signed out (all sessions removed)");
|
|
595
636
|
}
|
|
596
|
-
function help() { console.log(`tori \u2014 Tori CLI\n\n tori login [--base URL] sign in with GitHub (device flow)\n tori status [--json] balance + your AI keys\n tori key --limit 5 [--write env] [--file .env] [--json]\n tori stats [--json] your integration + developer program numbers\n tori init [--local] [--claude|--no-claude] [--cursor|--no-cursor] [--codex|--no-codex] wire Tori into this project (agents detected unless forced)\n tori check [paths...] [--json] run Tori's checks on changed files\n tori ledger [--project X|all] [--type a,b] [--since ISO] [--limit N] [--json]\n tori receipt <event_id|seq> fetch a receipt and verify it locally\n tori connector new [--label X] | list | revoke <id> Tori as a remote MCP connector (Claude Cowork etc.)\n tori standards [enable|disable <id…>] [--connector <label>] standards that apply to this project, or to a connector's\n tori rules [add "<rule>"|list|remove <id>] [--connector <label>] your own rules, in plain English\n tori init --base https://sandbox.earntori.com pin this repo to a Tori environment (.tori/project.json)\n tori logout\n`); }
|
|
637
|
+
function help() { console.log(`tori \u2014 Tori CLI\n\n tori login [--base URL] sign in with GitHub (device flow)\n tori status [--json] balance + your AI keys\n tori key --limit 5 [--write env] [--file .env] [--json]\n tori stats [--json] your integration + developer program numbers\n tori init [--local] [--claude|--no-claude] [--cursor|--no-cursor] [--codex|--no-codex] wire Tori into this project (agents detected unless forced)\n tori check [paths...] [--json] run Tori's checks on changed files\n tori ledger [--project X|all] [--type a,b] [--since ISO] [--limit N] [--json]\n tori receipt <event_id|seq> fetch a receipt and verify it locally\n tori connector new [--label X] | list | revoke <id> Tori as a remote MCP connector (Claude Cowork etc.)\n tori standards [enable|disable <id…>] [--connector <label>] standards that apply to this project, or to a connector's\n tori rules [add "<rule>"|list|remove <id>] [--connector <label>] your own rules, in plain English\n tori ignore add <glob…> | list | remove <glob> paths never sent to Tori (fixtures/, seeds/**, scratch); in .tori/project.json\n tori init --base https://sandbox.earntori.com pin this repo to a Tori environment (.tori/project.json)\n tori logout\n`); }
|
|
638
|
+
function ignoreCmd() {
|
|
639
|
+
const sub = args[1];
|
|
640
|
+
const pfile = join(".tori", "project.json");
|
|
641
|
+
let j = {};
|
|
642
|
+
try {
|
|
643
|
+
j = JSON.parse(readFileSync(pfile, "utf8"));
|
|
644
|
+
}
|
|
645
|
+
catch { }
|
|
646
|
+
const cur = Array.isArray(j.ignore) ? j.ignore.filter((x) => typeof x === "string") : [];
|
|
647
|
+
if (sub === "list" || !sub) {
|
|
648
|
+
if (has("json"))
|
|
649
|
+
return out({ ignore: cur }, cur.join("\n"));
|
|
650
|
+
console.log(cur.length ? cur.join("\n") : "No ignore patterns. Add one: tori ignore add fixtures/");
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
const pats = args.slice(2).filter((a) => !a.startsWith("--")).map((p) => p.trim()).filter(Boolean);
|
|
654
|
+
if (sub === "add") {
|
|
655
|
+
if (!pats.length)
|
|
656
|
+
die("Usage: tori ignore add <glob> [<glob>…]");
|
|
657
|
+
const next = Array.from(new Set([...cur, ...pats]));
|
|
658
|
+
writeJson(pfile, { ...j, ignore: next });
|
|
659
|
+
console.log(`Ignoring ${next.length} pattern(s) in this project; never sent to Tori:\n` + next.join("\n"));
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
if (sub === "remove") {
|
|
663
|
+
if (!pats.length)
|
|
664
|
+
die("Usage: tori ignore remove <glob>");
|
|
665
|
+
const next = cur.filter((p) => !pats.includes(p));
|
|
666
|
+
writeJson(pfile, { ...j, ignore: next });
|
|
667
|
+
console.log(next.length ? `Ignoring ${next.length} pattern(s):\n` + next.join("\n") : "No ignore patterns.");
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
die("Usage: tori ignore add <glob…> | list | remove <glob>");
|
|
671
|
+
}
|
|
597
672
|
(async () => {
|
|
598
673
|
switch (cmd) {
|
|
599
674
|
case "login": return login();
|
|
600
675
|
case "status": return status();
|
|
601
676
|
case "init": return init();
|
|
602
677
|
case "check": return check();
|
|
678
|
+
case "ignore": return ignoreCmd();
|
|
603
679
|
case "ledger": return ledger();
|
|
604
680
|
case "receipt": return receipt();
|
|
605
681
|
case "connector": return connector();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@earntori/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.17",
|
|
4
4
|
"description": "Tori CLI — holds your coding agent to a standard: checks before it calls a task done, each finding with its fix, on a signed record you can verify offline.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|