@earntori/cli 0.2.17 → 0.2.19
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 +35 -12
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -56,7 +56,7 @@ function out(o, human) { console.log(json ? JSON.stringify(o, null, 2) : human);
|
|
|
56
56
|
function die(msg) { console.error(json ? JSON.stringify({ error: msg }) : `\u2717 ${msg}`); process.exit(1); }
|
|
57
57
|
const usd = (c) => `$${(c / 100).toFixed(2)}`;
|
|
58
58
|
async function api(cfg, method, path, body) {
|
|
59
|
-
const r = await fetch(`${cfg.base}${path}`, { method, headers: { Authorization: `Bearer ${cfg.token}`, "Content-Type": "application/json", "User-Agent":
|
|
59
|
+
const r = await fetch(`${cfg.base}${path}`, { method, headers: { Authorization: `Bearer ${cfg.token}`, "Content-Type": "application/json", "User-Agent": userAgent() }, body: body ? JSON.stringify(body) : undefined });
|
|
60
60
|
const t = await r.text();
|
|
61
61
|
let j = null;
|
|
62
62
|
try {
|
|
@@ -162,8 +162,9 @@ function writeJson(p, o) { mkdirSync(dirname(resolve(p)), { recursive: true });
|
|
|
162
162
|
// (Claude Code and Cursor: always; Codex: when it is installed or present in the repo, or --codex);
|
|
163
163
|
// `install` writes that harness's files and returns their paths. Add a harness = add a row.
|
|
164
164
|
// Pinned package versions written into agent config (B1b). CLI version = this package's own;
|
|
165
|
-
// MCP version is a constant: bump it in the same commit as a @earntori/mcp release.
|
|
166
|
-
|
|
165
|
+
// MCP version is a constant: bump it in the same commit as a @earntori/mcp release. Spec rev 97:
|
|
166
|
+
// scripts/check-pins.mjs fails `test` and `prepublishOnly` when it differs from packages/mcp's version.
|
|
167
|
+
const TORI_MCP_VERSION = "0.1.12";
|
|
167
168
|
function cliVersion(cliBin) {
|
|
168
169
|
try {
|
|
169
170
|
return JSON.parse(readFileSync(resolve(dirname(realpathSync(cliBin)), "..", "package.json"), "utf8")).version ?? "latest";
|
|
@@ -172,6 +173,13 @@ function cliVersion(cliBin) {
|
|
|
172
173
|
return "latest";
|
|
173
174
|
}
|
|
174
175
|
}
|
|
176
|
+
/** Spec rev 97: the User-Agent carries this package's own version, read once per process. */
|
|
177
|
+
let uaCache;
|
|
178
|
+
function userAgent() {
|
|
179
|
+
if (!uaCache)
|
|
180
|
+
uaCache = `@earntori/cli/${cliVersion(resolve(process.argv[1] ?? ""))}`;
|
|
181
|
+
return uaCache;
|
|
182
|
+
}
|
|
175
183
|
const withHarness = (mcp, id) => ({ ...mcp, env: { TORI_HARNESS: id } });
|
|
176
184
|
function mergeMcpJson(file, mcp) { const j = readJson(file) ?? {}; j.mcpServers = { ...(j.mcpServers ?? {}), tori: mcp }; writeJson(file, j); return file; }
|
|
177
185
|
function hookPresent(h, c) { return typeof h?.command === "string" && (/@earntori\/cli(@[^\s]+)? check/.test(h.command) || (c.local && h.command.includes(c.cliBin))); }
|
|
@@ -243,8 +251,14 @@ const HARNESSES = [
|
|
|
243
251
|
];
|
|
244
252
|
async function init() {
|
|
245
253
|
const pin = flag("base");
|
|
246
|
-
if (pin)
|
|
247
|
-
|
|
254
|
+
if (pin) {
|
|
255
|
+
let prev = {};
|
|
256
|
+
try {
|
|
257
|
+
prev = JSON.parse(readFileSync(join(".tori", "project.json"), "utf8"));
|
|
258
|
+
}
|
|
259
|
+
catch { }
|
|
260
|
+
writeJson(join(".tori", "project.json"), { ...prev, base: pin.replace(/\/$/, "") });
|
|
261
|
+
}
|
|
248
262
|
let cfg = loadCfg();
|
|
249
263
|
if (!cfg) {
|
|
250
264
|
console.log(pin ? `Not signed in for ${pin} \u2014 signing in first` : "Not signed in \u2014 signing in first");
|
|
@@ -283,18 +297,27 @@ async function init() {
|
|
|
283
297
|
(set.length === HARNESSES.length ? "" : "\n(Not detected: " + HARNESSES.filter((h) => !set.includes(h)).map((h) => `${h.label} \u2014 tori init --${h.id === "claude-code" ? "claude" : h.id}`).join("; ") + ".)") + next);
|
|
284
298
|
}
|
|
285
299
|
function repoIndex() { try {
|
|
286
|
-
const
|
|
300
|
+
const pats = ignorePatterns(process.cwd());
|
|
301
|
+
const out = execSync("git ls-files", { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).split("\n").filter(Boolean).filter((p) => !isIgnored(p, pats));
|
|
287
302
|
return out.length ? out.slice(0, 5000) : undefined;
|
|
288
303
|
}
|
|
289
304
|
catch {
|
|
290
305
|
return undefined;
|
|
291
306
|
} }
|
|
292
|
-
|
|
293
|
-
|
|
307
|
+
/** Spec rev 97 (amends rev 86): `.env.example` is skipped when it matches an ignore pattern, and when it is
|
|
308
|
+
* read only variable names leave the machine, never values. Names are taken with the same pattern the one
|
|
309
|
+
* rule that uses them applies, so the check is unchanged. */
|
|
310
|
+
function envExample() {
|
|
311
|
+
try {
|
|
312
|
+
if (!existsSync(".env.example") || isIgnored(".env.example", ignorePatterns(process.cwd())))
|
|
313
|
+
return undefined;
|
|
314
|
+
const names = readFileSync(".env.example", "utf8").match(/^\s*[A-Z][A-Z0-9_]+\s*=/gm) ?? [];
|
|
315
|
+
return names.map((l) => l.replace(/\s*=.*$/, "").trim() + "=").join("\n").slice(0, 20000);
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
return undefined;
|
|
319
|
+
}
|
|
294
320
|
}
|
|
295
|
-
catch {
|
|
296
|
-
return undefined;
|
|
297
|
-
} }
|
|
298
321
|
const CODE_EXT = /\.(ts|tsx|js|jsx|mjs|cjs|py|go|rb|php|java|kt|cs)$/i;
|
|
299
322
|
function projectId() {
|
|
300
323
|
try {
|
|
@@ -439,7 +462,7 @@ async function check() {
|
|
|
439
462
|
try {
|
|
440
463
|
const body0 = { files, project: projectId(), repo_index: repoIndex(), env_example: envExample() };
|
|
441
464
|
dbg(`request: ${JSON.stringify(body0).length} bytes, index ${body0.repo_index?.length ?? 0} paths -> ${cfg.base}`);
|
|
442
|
-
const res = await fetch(`${cfg.base}/api/v1/checks/run`, { method: "POST", headers: { Authorization: `Bearer ${cfg.token}`, "Content-Type": "application/json", "User-Agent":
|
|
465
|
+
const res = await fetch(`${cfg.base}/api/v1/checks/run`, { method: "POST", headers: { Authorization: `Bearer ${cfg.token}`, "Content-Type": "application/json", "User-Agent": userAgent() }, body: JSON.stringify(body0) });
|
|
443
466
|
dbg(`response: ${res.status}`);
|
|
444
467
|
const t = await res.text();
|
|
445
468
|
if (!res.ok)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@earntori/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.19",
|
|
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",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"scripts": {
|
|
18
18
|
"build": "tsc -p tsconfig.json && chmod +x dist/index.js",
|
|
19
19
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
20
|
-
"test": "
|
|
20
|
+
"test": "node scripts/check-pins.mjs",
|
|
21
|
+
"prepublishOnly": "node scripts/check-pins.mjs"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
24
|
"@types/node": "^20.19.43",
|