agent-roast 0.8.0 → 0.8.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/README.md +17 -4
- package/dist/{chunk-C423TSZF.js → chunk-U7OCVA3D.js} +93 -67
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -106,12 +106,12 @@ regressions) may appear in the report/summary rather than as an inline PR annota
|
|
|
106
106
|
Use a separate SARIF category for introduced-findings review; it does not represent
|
|
107
107
|
a full scan of all outstanding alerts.
|
|
108
108
|
|
|
109
|
-
Install 0.8.
|
|
109
|
+
Install 0.8.1: `npx agent-roast@0.8.1 review --base origin/main`. For local development,
|
|
110
110
|
run `npm run build` and use `node dist/cli.js`.
|
|
111
111
|
|
|
112
112
|
### Precise exceptions (since 0.8.0)
|
|
113
113
|
|
|
114
|
-
Use `npx agent-roast@0.8.
|
|
114
|
+
Use `npx agent-roast@0.8.1 check --format json`, or build this checkout with
|
|
115
115
|
`npm run build` and run `node dist/cli.js`.
|
|
116
116
|
|
|
117
117
|
Some skipped integrations or abstract stubs are intentional. In 0.8.0 you can accept
|
|
@@ -278,6 +278,11 @@ The JSON schema version for context reviews is now `1.1.0`.
|
|
|
278
278
|
The generated hook uses the locally installed CLI (`--no-install`) and blocks on configured error rules instead of scoring
|
|
279
279
|
old commits. It preserves an existing pre-commit hook.
|
|
280
280
|
|
|
281
|
+
`init` resolves the repository root even when run from a package/subdirectory, so
|
|
282
|
+
its policy is used by `check` and its workflow can be discovered by GitHub. Outside
|
|
283
|
+
a Git repository, initialization uses the supplied directory. Its output shows the
|
|
284
|
+
actual destination and existing policy/hooks are preserved.
|
|
285
|
+
|
|
281
286
|
### Configure what blocks a change
|
|
282
287
|
|
|
283
288
|
Create `.agentroastrc.json` (or run `npx agent-roast init`):
|
|
@@ -342,7 +347,7 @@ jobs:
|
|
|
342
347
|
|
|
343
348
|
To pilot the Action without blocking on findings, set `advisory: true`. It passes
|
|
344
349
|
an explicit empty fail-on list; invalid configuration, Git errors and incomplete
|
|
345
|
-
scans still fail. The `v1` Action installs 0.8.
|
|
350
|
+
scans still fail. The `v1` Action installs 0.8.1. The CLI equivalent is `--fail-on ''`.
|
|
346
351
|
|
|
347
352
|
> **Security Note:** `agent-roast` runs in an isolated runner directory (`$RUNNER_TEMP`) with `--ignore-scripts` to neutralize malicious `.npmrc` files in untrusted pull requests. `pull_request_target` is not supported.
|
|
348
353
|
|
|
@@ -393,6 +398,11 @@ Rust raw strings/lifetimes and Java/Kotlin text blocks. Contiguous comments, Pyt
|
|
|
393
398
|
docstrings and multiline empty handlers are recognized. Template interpolation, complex language syntax and context outside
|
|
394
399
|
the added diff in legacy audit modes are not fully parsed. Custom test API aliases,
|
|
395
400
|
computed property calls and type/import resolution are not handled. Panic loops are an observational history heuristic.
|
|
401
|
+
Test registration options such as Node's `test('name', { skip: true }, fn)` and
|
|
402
|
+
`{ only: true }` are currently not inspected; use explicit `.skip`/`.only` APIs and
|
|
403
|
+
the runner's CI safeguards. Regexp masking is contextual, not a full JavaScript
|
|
404
|
+
parser. Formatting across contiguous lines is supported for casts, empty catches
|
|
405
|
+
and placeholder errors, but legacy added-line audits cannot recover missing hunks.
|
|
396
406
|
The discipline score summarizes added history; it does not certify current code quality.
|
|
397
407
|
`check` reports actionable findings without assigning a personality or quality score.
|
|
398
408
|
History attribution is based on explicit text/identity heuristics; it does not prove
|
|
@@ -416,13 +426,16 @@ are exercised on Node 18/20/22 using `AGENT_ROAST_TEST_NODE`.
|
|
|
416
426
|
npm ci
|
|
417
427
|
npm run typecheck
|
|
418
428
|
npm test
|
|
429
|
+
|
|
430
|
+
# Optional end-to-end CLI checks in disposable Git repositories
|
|
431
|
+
node scripts/verify-user-workflows.mjs dist/cli.js
|
|
419
432
|
```
|
|
420
433
|
|
|
421
434
|
`npm test` builds the distribution first so CLI integration and bundle checks run
|
|
422
435
|
against current code. Regression tests use disposable Git repositories. The programmatic
|
|
423
436
|
`auditPullRequest({ staged: true })` API retains the legacy added-lines contract;
|
|
424
437
|
use `reviewStagedChanges()` for the new context comparison and `ReviewResult`.
|
|
425
|
-
The composite Action installs exactly 0.8.
|
|
438
|
+
The composite Action installs exactly 0.8.1. For local development, use
|
|
426
439
|
`node dist/cli.js --staged` after building.
|
|
427
440
|
|
|
428
441
|
### Author & Support
|
|
@@ -576,6 +576,8 @@ var SourceMasker = class {
|
|
|
576
576
|
triple = false;
|
|
577
577
|
verbatim = false;
|
|
578
578
|
previousLine = 0;
|
|
579
|
+
tokenPrefix = "";
|
|
580
|
+
parentheses = [];
|
|
579
581
|
python;
|
|
580
582
|
javascript;
|
|
581
583
|
rust;
|
|
@@ -602,12 +604,14 @@ var SourceMasker = class {
|
|
|
602
604
|
this.rawEnd = "";
|
|
603
605
|
this.triple = false;
|
|
604
606
|
this.verbatim = false;
|
|
607
|
+
this.tokenPrefix = "";
|
|
608
|
+
this.parentheses.length = 0;
|
|
605
609
|
}
|
|
606
610
|
this.previousLine = number;
|
|
607
611
|
const code = Array(line.length).fill(" ");
|
|
608
612
|
const comments = Array(line.length).fill(" ");
|
|
609
613
|
let i = 0;
|
|
610
|
-
let prefix =
|
|
614
|
+
let prefix = this.tokenPrefix;
|
|
611
615
|
const appendPrefix = (text) => {
|
|
612
616
|
for (const char of text) {
|
|
613
617
|
if (/\s/.test(char)) {
|
|
@@ -706,7 +710,7 @@ var SourceMasker = class {
|
|
|
706
710
|
appendPrefix(" literal ");
|
|
707
711
|
continue;
|
|
708
712
|
}
|
|
709
|
-
if (this.javascript && char === "/" && (/(
|
|
713
|
+
if (this.javascript && char === "/" && (/(?:=>|[=(:,[!&|?{;]|\breturn|\byield|\bthrow)\s*$/.test(prefix) || !prefix.trim())) {
|
|
710
714
|
let j = i + 1;
|
|
711
715
|
let inClass = false;
|
|
712
716
|
for (; j < line.length; j++) {
|
|
@@ -727,10 +731,19 @@ var SourceMasker = class {
|
|
|
727
731
|
}
|
|
728
732
|
}
|
|
729
733
|
code[i] = char;
|
|
734
|
+
if (this.javascript && char === "(") {
|
|
735
|
+
const control = /(?<![\w$])(?:if|while|for|with|switch|catch)\s*$/.exec(prefix);
|
|
736
|
+
this.parentheses.push(Boolean(control && !/\.\s*$/.test(prefix.slice(0, control.index))));
|
|
737
|
+
} else if (this.javascript && char === ")" && this.parentheses.pop()) {
|
|
738
|
+
prefix = "; ";
|
|
739
|
+
i++;
|
|
740
|
+
continue;
|
|
741
|
+
}
|
|
730
742
|
appendPrefix(char);
|
|
731
743
|
i++;
|
|
732
744
|
}
|
|
733
745
|
if (this.quote !== "`" && !this.triple && !this.verbatim && !continued) this.quote = "";
|
|
746
|
+
this.tokenPrefix = this.javascript ? (prefix + " ").slice(-64) : "";
|
|
734
747
|
return { code: code.join(""), comments: comments.join(""), templateStarts, blockStarts };
|
|
735
748
|
}
|
|
736
749
|
};
|
|
@@ -1139,7 +1152,7 @@ var PYTHON_TRIVIAL_ASSERT_PATTERNS = [
|
|
|
1139
1152
|
{ regex: /\bself\s*\.\s*assertEqual\s*\(\s*(?:1\s*,\s*1|True\s*,\s*True)\s*\)/, name: "trivial assert (self.assertEqual(1, 1))" }
|
|
1140
1153
|
];
|
|
1141
1154
|
var JS_STUB_PATTERNS = [
|
|
1142
|
-
{ regex: /\bthrow\s+new\s+Error\s*\(\s*["'](?:TODO\b|Not implemented\b|to be implemented\b|stub\b|implement me\b)/i, name: "unimplemented stub (throw new Error('Not implemented'))" }
|
|
1155
|
+
{ regex: /\bthrow\s+new\s+Error\s*\(\s*["'`](?:TODO(?=\s*(?:["'`:]|implement\b))|Not implemented\b|to be implemented\b|stub\b|implement me\b)/i, name: "unimplemented stub (throw new Error('Not implemented'))" }
|
|
1143
1156
|
];
|
|
1144
1157
|
var PYTHON_STUB_PATTERNS = [
|
|
1145
1158
|
{ regex: /\braise\s+NotImplementedError\b/, name: "unimplemented stub (raise NotImplementedError)" },
|
|
@@ -1251,22 +1264,6 @@ function auditFileDiffs(files, commitHash = "HEAD", commitDate = (/* @__PURE__ *
|
|
|
1251
1264
|
infractions.push({ type: "type-escape", file: file.path, lineNumber: added.lineNumber, lineSnippet: rawLine.trim(), commitHash, commitDate, reason: "linter suppression (eslint-disable)" });
|
|
1252
1265
|
foundEscape = true;
|
|
1253
1266
|
}
|
|
1254
|
-
if (typescript && !foundEscape && !isComment) {
|
|
1255
|
-
for (const rule of CODE_TYPE_ESCAPE_PATTERNS) {
|
|
1256
|
-
if (rule.regex.test(cleanedLine)) {
|
|
1257
|
-
infractions.push({
|
|
1258
|
-
type: "type-escape",
|
|
1259
|
-
file: file.path,
|
|
1260
|
-
lineNumber: added.lineNumber,
|
|
1261
|
-
lineSnippet: rawLine.trim(),
|
|
1262
|
-
commitHash,
|
|
1263
|
-
commitDate,
|
|
1264
|
-
reason: rule.name
|
|
1265
|
-
});
|
|
1266
|
-
break;
|
|
1267
|
-
}
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
1267
|
if (python && !isComment && isTestFile(file.path)) {
|
|
1271
1268
|
for (const rule of PYTHON_TRIVIAL_ASSERT_PATTERNS) {
|
|
1272
1269
|
if (rule.regex.test(cleanedLine)) {
|
|
@@ -1283,40 +1280,55 @@ function auditFileDiffs(files, commitHash = "HEAD", commitDate = (/* @__PURE__ *
|
|
|
1283
1280
|
}
|
|
1284
1281
|
}
|
|
1285
1282
|
}
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1283
|
+
}
|
|
1284
|
+
let source = "";
|
|
1285
|
+
let code = "";
|
|
1286
|
+
let raw = "";
|
|
1287
|
+
const offsets = [];
|
|
1288
|
+
for (let i = 0; i < maskedLines.length; i++) {
|
|
1289
|
+
const separator = i ? maskedLines[i].number === maskedLines[i - 1].number + 1 ? "\n" : "\0" : "";
|
|
1290
|
+
source += separator;
|
|
1291
|
+
code += separator;
|
|
1292
|
+
raw += separator;
|
|
1293
|
+
offsets.push(source.length);
|
|
1294
|
+
source += maskedLines[i].testCode;
|
|
1295
|
+
code += maskedLines[i].code;
|
|
1296
|
+
raw += maskedLines[i].raw;
|
|
1297
|
+
}
|
|
1298
|
+
const evidence = (index, length) => {
|
|
1299
|
+
let low = 0;
|
|
1300
|
+
let high = offsets.length;
|
|
1301
|
+
while (low + 1 < high) {
|
|
1302
|
+
const middle = low + high >>> 1;
|
|
1303
|
+
if (offsets[middle] <= index) low = middle;
|
|
1304
|
+
else high = middle;
|
|
1305
|
+
}
|
|
1306
|
+
let end = low;
|
|
1307
|
+
while (end + 1 < offsets.length && offsets[end + 1] < index + length) end++;
|
|
1308
|
+
return { lineNumber: maskedLines[low].number, lineSnippet: maskedLines.slice(low, end + 1).map((line) => line.raw.trim()).join(" ") };
|
|
1309
|
+
};
|
|
1310
|
+
const reportedStubs = /* @__PURE__ */ new Set();
|
|
1311
|
+
for (const rule of stubs) {
|
|
1312
|
+
for (const match of raw.matchAll(new RegExp(rule.regex.source, rule.regex.flags + "g"))) {
|
|
1313
|
+
if (code[match.index] !== raw[match.index]) continue;
|
|
1314
|
+
const location = evidence(match.index, match[0].length);
|
|
1315
|
+
if (reportedStubs.has(location.lineNumber)) continue;
|
|
1316
|
+
reportedStubs.add(location.lineNumber);
|
|
1317
|
+
infractions.push({ type: "stub-abandonment", file: file.path, ...location, commitHash, commitDate, reason: rule.name });
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
if (typescript) {
|
|
1321
|
+
const reported = new Set(infractions.slice(firstFinding).filter((f) => f.type === "type-escape").map((f) => f.lineNumber));
|
|
1322
|
+
for (const rule of CODE_TYPE_ESCAPE_PATTERNS) {
|
|
1323
|
+
for (const match of code.matchAll(new RegExp(rule.regex.source, "g"))) {
|
|
1324
|
+
const location = evidence(match.index, match[0].length);
|
|
1325
|
+
if (reported.has(location.lineNumber)) continue;
|
|
1326
|
+
reported.add(location.lineNumber);
|
|
1327
|
+
infractions.push({ type: "type-escape", file: file.path, ...location, commitHash, commitDate, reason: rule.name });
|
|
1302
1328
|
}
|
|
1303
1329
|
}
|
|
1304
1330
|
}
|
|
1305
1331
|
if (javascript) {
|
|
1306
|
-
let source = "";
|
|
1307
|
-
const offsets = [];
|
|
1308
|
-
for (let i = 0; i < maskedLines.length; i++) {
|
|
1309
|
-
if (i) source += maskedLines[i].number === maskedLines[i - 1].number + 1 ? "\n" : "\0";
|
|
1310
|
-
offsets.push(source.length);
|
|
1311
|
-
source += maskedLines[i].testCode;
|
|
1312
|
-
}
|
|
1313
|
-
let row = 0;
|
|
1314
|
-
const evidence = (index, length) => {
|
|
1315
|
-
while (row + 1 < offsets.length && offsets[row + 1] <= index) row++;
|
|
1316
|
-
let end = row;
|
|
1317
|
-
while (end + 1 < offsets.length && offsets[end + 1] < index + length) end++;
|
|
1318
|
-
return { lineNumber: maskedLines[row].number, lineSnippet: maskedLines.slice(row, end + 1).map((line) => line.raw.trim()).join(" ") };
|
|
1319
|
-
};
|
|
1320
1332
|
for (const match of source.matchAll(JS_TEST_API)) {
|
|
1321
1333
|
let previous = match.index - 1;
|
|
1322
1334
|
while (previous >= 0 && /\s/.test(source[previous])) previous--;
|
|
@@ -1335,34 +1347,35 @@ function auditFileDiffs(files, commitHash = "HEAD", commitDate = (/* @__PURE__ *
|
|
|
1335
1347
|
});
|
|
1336
1348
|
}
|
|
1337
1349
|
if (isTestFile(file.path)) {
|
|
1338
|
-
row = 0;
|
|
1339
1350
|
for (const rule of JS_TRIVIAL_ASSERT_PATTERNS) {
|
|
1340
1351
|
for (const match of source.matchAll(new RegExp(rule.regex.source, "g"))) {
|
|
1341
1352
|
infractions.push({ type: "trivial-assert", file: file.path, ...evidence(match.index, match[0].length), commitHash, commitDate, reason: rule.name });
|
|
1342
1353
|
}
|
|
1343
|
-
row = 0;
|
|
1344
1354
|
}
|
|
1345
1355
|
}
|
|
1346
1356
|
}
|
|
1357
|
+
if (braceCatches) {
|
|
1358
|
+
for (const match of code.matchAll(/(?<![\w$.])catch\s*(?:\(\s*[^()\s\0][^()\0]*\))?\s*\{\s*\}/g)) {
|
|
1359
|
+
infractions.push({
|
|
1360
|
+
type: "swallowed-error",
|
|
1361
|
+
file: file.path,
|
|
1362
|
+
...evidence(match.index, match[0].length),
|
|
1363
|
+
commitHash,
|
|
1364
|
+
commitDate,
|
|
1365
|
+
reason: match[0].includes("\n") ? "empty multi-line catch block" : "empty catch block (catch {})"
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1347
1369
|
for (let index = 0; index < maskedLines.length; index++) {
|
|
1348
1370
|
const start = maskedLines[index];
|
|
1349
|
-
const catches = braceCatches ? [...start.code.matchAll(/(?<![\w$.])catch\s*(?:\(\s*[^)\s][^)]*\))?\s*\{/g)] : [];
|
|
1350
|
-
for (const match of catches) {
|
|
1351
|
-
if (/^\s*}/.test(start.code.slice(match.index + match[0].length))) {
|
|
1352
|
-
infractions.push({ type: "swallowed-error", file: file.path, lineNumber: start.number, lineSnippet: start.raw.trim(), commitHash, commitDate, reason: "empty catch block (catch {})" });
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
const lastCatch = catches.at(-1);
|
|
1356
|
-
const isCatch = lastCatch && /^\s*$/.test(start.code.slice(lastCatch.index + lastCatch[0].length));
|
|
1357
1371
|
const inlineExcept = python && /^\s*except(?:\*?\s+[^:]+)?:\s*pass\s*;?\s*$/.test(start.code);
|
|
1358
1372
|
if (inlineExcept) infractions.push({ type: "swallowed-error", file: file.path, lineNumber: start.number, lineSnippet: start.raw.trim(), commitHash, commitDate, reason: "silent python error swallow (except: pass)" });
|
|
1359
1373
|
const isExcept = python && /^\s*except(?:\*?\s+[^:]+)?:\s*$/.test(start.code);
|
|
1360
|
-
if (!
|
|
1374
|
+
if (!isExcept) continue;
|
|
1361
1375
|
let next = index + 1;
|
|
1362
1376
|
while (next < maskedLines.length && maskedLines[next].number === maskedLines[next - 1].number + 1 && !maskedLines[next].code.trim()) next++;
|
|
1363
1377
|
const end = maskedLines[next];
|
|
1364
1378
|
if (!end || end.number !== maskedLines[next - 1].number + 1) continue;
|
|
1365
|
-
const closesCatch = isCatch && /^\s*}/.test(end.code);
|
|
1366
1379
|
let closesExcept = isExcept && /^\s*pass\s*;?\s*$/.test(end.code);
|
|
1367
1380
|
if (closesExcept) {
|
|
1368
1381
|
const indent = start.raw.search(/\S/);
|
|
@@ -1371,14 +1384,14 @@ function auditFileDiffs(files, commitHash = "HEAD", commitDate = (/* @__PURE__ *
|
|
|
1371
1384
|
while (after < maskedLines.length && maskedLines[after].number === maskedLines[after - 1].number + 1 && !maskedLines[after].code.trim()) after++;
|
|
1372
1385
|
if (after < maskedLines.length && maskedLines[after].number === maskedLines[after - 1].number + 1 && maskedLines[after].raw.search(/\S/) > indent) closesExcept = false;
|
|
1373
1386
|
}
|
|
1374
|
-
if (
|
|
1387
|
+
if (closesExcept) infractions.push({
|
|
1375
1388
|
type: "swallowed-error",
|
|
1376
1389
|
file: file.path,
|
|
1377
1390
|
lineNumber: start.number,
|
|
1378
1391
|
lineSnippet: maskedLines.slice(index, next + 1).map((line) => line.raw.trim()).join(" "),
|
|
1379
1392
|
commitHash,
|
|
1380
1393
|
commitDate,
|
|
1381
|
-
reason:
|
|
1394
|
+
reason: "silent multi-line python error swallow"
|
|
1382
1395
|
});
|
|
1383
1396
|
}
|
|
1384
1397
|
const ordered = infractions.splice(firstFinding).sort((left, right) => (left.lineNumber || 0) - (right.lineNumber || 0));
|
|
@@ -2184,11 +2197,24 @@ var hasEntry = (filename) => {
|
|
|
2184
2197
|
}
|
|
2185
2198
|
};
|
|
2186
2199
|
async function initProject(options = {}) {
|
|
2187
|
-
|
|
2200
|
+
let cwd = fs4.realpathSync(path3.resolve(options.cwd || process.cwd()));
|
|
2201
|
+
const root = spawnSync2("git", [...HERMETIC_GIT_FLAGS, "rev-parse", "--show-toplevel"], {
|
|
2202
|
+
cwd,
|
|
2203
|
+
env: { ...getHermeticGitEnv(), LC_ALL: "C" },
|
|
2204
|
+
encoding: "utf8",
|
|
2205
|
+
timeout: 3e4,
|
|
2206
|
+
maxBuffer: 8192,
|
|
2207
|
+
windowsHide: true
|
|
2208
|
+
});
|
|
2209
|
+
if (root.error) throw new ConfigError("Cannot resolve the repository root for initialization.");
|
|
2210
|
+
if (root.status === 0) cwd = fs4.realpathSync(gitOutputPath(root.stdout));
|
|
2211
|
+
else if (root.status !== 128 || !root.stderr.includes("not a git repository")) {
|
|
2212
|
+
throw new ConfigError("Cannot resolve a working repository root for initialization.");
|
|
2213
|
+
}
|
|
2188
2214
|
const created = [];
|
|
2189
2215
|
const skipped = [];
|
|
2190
|
-
const publish = (
|
|
2191
|
-
(createNewFile(
|
|
2216
|
+
const publish = (root2, relative2, label, content, mode) => {
|
|
2217
|
+
(createNewFile(root2, relative2, content, mode) ? created : skipped).push(label);
|
|
2192
2218
|
};
|
|
2193
2219
|
if ([".agentroastrc.json", "agent-roast.config.json", ".agentroastrc"].some((name) => hasEntry(path3.join(cwd, name)))) {
|
|
2194
2220
|
skipped.push(".agentroastrc.json");
|
|
@@ -2220,7 +2246,7 @@ async function initProject(options = {}) {
|
|
|
2220
2246
|
} else publish(commonDir, relative2, ".git/hooks/pre-commit", PRE_COMMIT_HOOK_TEMPLATE, 493);
|
|
2221
2247
|
}
|
|
2222
2248
|
}
|
|
2223
|
-
return { created, skipped };
|
|
2249
|
+
return { directory: cwd, created, skipped };
|
|
2224
2250
|
}
|
|
2225
2251
|
|
|
2226
2252
|
// src/badge.ts
|
package/dist/cli.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
roastRepository,
|
|
23
23
|
terminalText,
|
|
24
24
|
writeBaseline
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-U7OCVA3D.js";
|
|
26
26
|
|
|
27
27
|
// src/cli.ts
|
|
28
28
|
import { Command } from "commander";
|
|
@@ -254,7 +254,7 @@ program.command("init").description("Initialize .agentroastrc.json and CI/hook c
|
|
|
254
254
|
hook: opts.hook
|
|
255
255
|
});
|
|
256
256
|
if (res.created.length > 0) {
|
|
257
|
-
console.log(`Initialized agent-roast in ${terminalText(
|
|
257
|
+
console.log(`Initialized agent-roast in ${terminalText(res.directory)}:`);
|
|
258
258
|
for (const file of res.created) {
|
|
259
259
|
console.log(` + Created ${terminalText(file)}`);
|
|
260
260
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED