agentloopkit 0.24.4 → 0.25.0
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 +15 -6
- package/dist/cli/index.js +134 -38
- package/dist/cli/index.js.map +1 -1
- package/dist/templates/root/AGENTLOOP.md +2 -0
- package/dist/templates/root/AGENTS.md +2 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -49,11 +49,19 @@ npx agentloopkit init
|
|
|
49
49
|
|
|
50
50
|
`init` writes files into the current directory. Do not run it from `~` unless you intend to configure your home directory. `--dry-run` previews the file changes without writing them.
|
|
51
51
|
|
|
52
|
+
If you want AgentLoopKit for your local agent workflow but do not want to commit the generated harness:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npx agentloopkit init --local-only
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`--local-only` writes the same files, then adds a marked block to this clone's `.git/info/exclude` for `.agentloop/`, `AGENTS.md`, `AGENTLOOP.md`, and `agentloop.config.json`. It does not edit `.gitignore`, global Git config, shell profiles, or files outside the current repo.
|
|
59
|
+
|
|
52
60
|
Pin the current version when you need repeatable CI or team setup:
|
|
53
61
|
|
|
54
62
|
```bash
|
|
55
|
-
npx --yes agentloopkit@0.
|
|
56
|
-
npx --yes agentloopkit@0.
|
|
63
|
+
npx --yes agentloopkit@0.25.0 version
|
|
64
|
+
npx --yes agentloopkit@0.25.0 init
|
|
57
65
|
```
|
|
58
66
|
|
|
59
67
|
Run the CLI after install:
|
|
@@ -87,10 +95,10 @@ npx agentloopkit completion powershell
|
|
|
87
95
|
```
|
|
88
96
|
|
|
89
97
|
<p align="center">
|
|
90
|
-
<img src="https://raw.githubusercontent.com/abhiyoheswaran1/AgentLoopKit/main/docs/assets/readme/agentloopkit-cli.gif" alt="Terminal demo running AgentLoopKit init, task
|
|
98
|
+
<img src="https://raw.githubusercontent.com/abhiyoheswaran1/AgentLoopKit/main/docs/assets/readme/agentloopkit-cli.gif" alt="Terminal demo running AgentLoopKit init, doctor, task contract creation, task status, verification, handoff, gates, HTML report, and badge commands" width="100%">
|
|
91
99
|
</p>
|
|
92
100
|
|
|
93
|
-
The
|
|
101
|
+
The terminal demo is generated from committed VHS sources in this repository.
|
|
94
102
|
|
|
95
103
|
Pinned team usage:
|
|
96
104
|
|
|
@@ -116,6 +124,7 @@ pnpm build
|
|
|
116
124
|
| `agentloop init` | Generate the repo harness and config |
|
|
117
125
|
| `agentloop init --dry-run` | Preview generated files without writing them |
|
|
118
126
|
| `agentloop init --force` | Allow initialization when the current directory is your home directory |
|
|
127
|
+
| `agentloop init --local-only` | Generate the harness but exclude it from this clone's git status |
|
|
119
128
|
| `agentloop doctor` | Check setup health, template version, commands, git state, and risk categories |
|
|
120
129
|
| `agentloop create-task` | Create a task contract in `.agentloop/tasks/` |
|
|
121
130
|
| `agentloop task list` | List task contracts and show the pinned active task |
|
|
@@ -384,7 +393,7 @@ See `docs/ci-summary.md`.
|
|
|
384
393
|
```bash
|
|
385
394
|
agentloop release-notes
|
|
386
395
|
agentloop release-notes --from v0.19.0 --to HEAD
|
|
387
|
-
agentloop release-notes --release-version 0.
|
|
396
|
+
agentloop release-notes --release-version 0.25.0
|
|
388
397
|
agentloop release-notes --json
|
|
389
398
|
agentloop release-notes --write
|
|
390
399
|
```
|
|
@@ -450,7 +459,7 @@ Use `agentloop check-gates --strict` as a review-evidence gate in pull request C
|
|
|
450
459
|
|
|
451
460
|
CI-generated verification reports include GitHub Actions provenance when available, so reviewers can trace an artifact back to the workflow run that created it.
|
|
452
461
|
|
|
453
|
-
See `docs/github-actions.md`, `examples/github-actions/`, `examples/gitlab-ci/`, and `examples/buildkite/` for copy-pasteable workflows. Pin `agentloopkit@0.
|
|
462
|
+
See `docs/github-actions.md`, `examples/github-actions/`, `examples/gitlab-ci/`, and `examples/buildkite/` for copy-pasteable workflows. Pin `agentloopkit@0.25.0` or a newer vetted release when reproducibility matters.
|
|
454
463
|
|
|
455
464
|
## PR Summaries
|
|
456
465
|
|
package/dist/cli/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { Command } from "commander";
|
|
|
8
8
|
|
|
9
9
|
// src/core/init.ts
|
|
10
10
|
import path6 from "path";
|
|
11
|
-
import { readdir as readdir3, realpath } from "fs/promises";
|
|
11
|
+
import { readdir as readdir3, realpath, stat as stat2 } from "fs/promises";
|
|
12
12
|
import { homedir } from "os";
|
|
13
13
|
|
|
14
14
|
// src/core/constants.ts
|
|
@@ -342,6 +342,21 @@ async function listTemplateFiles() {
|
|
|
342
342
|
}
|
|
343
343
|
|
|
344
344
|
// src/core/init.ts
|
|
345
|
+
var LOCAL_ONLY_EXCLUDE_START = "# agentloopkit:local-only:start";
|
|
346
|
+
var LOCAL_ONLY_EXCLUDE_END = "# agentloopkit:local-only:end";
|
|
347
|
+
var LOCAL_ONLY_NOTICE_START = "<!-- agentloopkit:local-only:start -->";
|
|
348
|
+
var LOCAL_ONLY_NOTICE_END = "<!-- agentloopkit:local-only:end -->";
|
|
349
|
+
var LOCAL_ONLY_EXCLUDE_PATTERNS = [
|
|
350
|
+
`${AGENTLOOP_DIR}/`,
|
|
351
|
+
AGENTS_FILE,
|
|
352
|
+
AGENTLOOP_FILE,
|
|
353
|
+
CONFIG_FILE
|
|
354
|
+
];
|
|
355
|
+
var LOCAL_ONLY_NOTICE = `${LOCAL_ONLY_NOTICE_START}
|
|
356
|
+
## Local-only AgentLoopKit harness
|
|
357
|
+
|
|
358
|
+
This AgentLoopKit setup is excluded by this clone's \`.git/info/exclude\`. Use these files for local agent work. Do not commit these AgentLoopKit files unless a maintainer intentionally converts the repo to a shared harness.
|
|
359
|
+
${LOCAL_ONLY_NOTICE_END}`;
|
|
345
360
|
async function writeGeneratedFile(filePath, content, result) {
|
|
346
361
|
if (await pathExists(filePath)) {
|
|
347
362
|
result.skipped.push(filePath);
|
|
@@ -395,6 +410,65 @@ ${section.trim()}
|
|
|
395
410
|
`);
|
|
396
411
|
result.updated.push(filePath);
|
|
397
412
|
}
|
|
413
|
+
async function resolveGitInfoExcludePath(cwd) {
|
|
414
|
+
const dotGitPath = path6.join(cwd, ".git");
|
|
415
|
+
const dotGitStat = await stat2(dotGitPath).catch(() => void 0);
|
|
416
|
+
if (!dotGitStat) return void 0;
|
|
417
|
+
if (dotGitStat.isDirectory()) {
|
|
418
|
+
return path6.join(dotGitPath, "info", "exclude");
|
|
419
|
+
}
|
|
420
|
+
if (!dotGitStat.isFile()) return void 0;
|
|
421
|
+
const gitFile = await readTextIfExists(dotGitPath);
|
|
422
|
+
const match = /^gitdir:\s*(.+)\s*$/m.exec(gitFile);
|
|
423
|
+
if (!match) return void 0;
|
|
424
|
+
const gitDir = match[1].trim();
|
|
425
|
+
const resolvedGitDir = path6.isAbsolute(gitDir) ? gitDir : path6.resolve(cwd, gitDir);
|
|
426
|
+
return path6.join(resolvedGitDir, "info", "exclude");
|
|
427
|
+
}
|
|
428
|
+
async function upsertLocalOnlyGitExclude(cwd, result) {
|
|
429
|
+
const excludePath = await resolveGitInfoExcludePath(cwd);
|
|
430
|
+
if (!excludePath) {
|
|
431
|
+
throw new Error(
|
|
432
|
+
"Local-only mode requires a Git repository because it writes to .git/info/exclude. Run git init first, or run agentloop init without --local-only."
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
result.localOnly = {
|
|
436
|
+
excludePath,
|
|
437
|
+
patterns: [...LOCAL_ONLY_EXCLUDE_PATTERNS]
|
|
438
|
+
};
|
|
439
|
+
const excludeExists = await pathExists(excludePath);
|
|
440
|
+
const existing = await readTextIfExists(excludePath);
|
|
441
|
+
if (existing.includes(LOCAL_ONLY_EXCLUDE_START)) return;
|
|
442
|
+
const block = [
|
|
443
|
+
LOCAL_ONLY_EXCLUDE_START,
|
|
444
|
+
"# AgentLoopKit local-only harness files for this clone.",
|
|
445
|
+
...LOCAL_ONLY_EXCLUDE_PATTERNS,
|
|
446
|
+
LOCAL_ONLY_EXCLUDE_END
|
|
447
|
+
].join("\n");
|
|
448
|
+
if (result.dryRun) {
|
|
449
|
+
(excludeExists ? result.updated : result.created).push(excludePath);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
const prefix = existing.trimEnd();
|
|
453
|
+
await writeTextFile(excludePath, `${prefix ? `${prefix}
|
|
454
|
+
|
|
455
|
+
` : ""}${block}
|
|
456
|
+
`);
|
|
457
|
+
(excludeExists ? result.updated : result.created).push(excludePath);
|
|
458
|
+
}
|
|
459
|
+
async function upsertLocalOnlyNotice(filePath, result) {
|
|
460
|
+
const existing = await readTextIfExists(filePath);
|
|
461
|
+
if (existing.includes(LOCAL_ONLY_NOTICE_START)) return;
|
|
462
|
+
if (result.dryRun) {
|
|
463
|
+
(existing ? result.updated : result.created).push(filePath);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
await writeTextFile(filePath, `${existing.trimEnd()}
|
|
467
|
+
|
|
468
|
+
${LOCAL_ONLY_NOTICE}
|
|
469
|
+
`);
|
|
470
|
+
(existing ? result.updated : result.created).push(filePath);
|
|
471
|
+
}
|
|
398
472
|
async function resolveComparablePath(filePath) {
|
|
399
473
|
try {
|
|
400
474
|
return await realpath(filePath);
|
|
@@ -420,6 +494,9 @@ async function initializeAgentLoop(options) {
|
|
|
420
494
|
"Refusing to initialize your home directory. Run this inside a project repository, or pass --force if you intentionally want AgentLoopKit files in your home directory."
|
|
421
495
|
);
|
|
422
496
|
}
|
|
497
|
+
if (options.localOnly) {
|
|
498
|
+
await upsertLocalOnlyGitExclude(cwd, result);
|
|
499
|
+
}
|
|
423
500
|
const packageManager = await detectPackageManager(cwd);
|
|
424
501
|
const projectType = await detectProjectType(cwd);
|
|
425
502
|
const projectName = await detectProjectName(cwd);
|
|
@@ -438,7 +515,8 @@ async function initializeAgentLoop(options) {
|
|
|
438
515
|
lintCommand: commands.lint || "not configured",
|
|
439
516
|
typecheckCommand: commands.typecheck || "not configured",
|
|
440
517
|
buildCommand: commands.build || "not configured",
|
|
441
|
-
formatCommand: commands.format || "not configured"
|
|
518
|
+
formatCommand: commands.format || "not configured",
|
|
519
|
+
localOnlyInstructions: options.localOnly ? LOCAL_ONLY_NOTICE : ""
|
|
442
520
|
};
|
|
443
521
|
for (const group of TEMPLATE_GROUPS) {
|
|
444
522
|
if (group === "tasks") continue;
|
|
@@ -480,6 +558,10 @@ async function initializeAgentLoop(options) {
|
|
|
480
558
|
await readTemplate("root/AGENTLOOP.md", values),
|
|
481
559
|
result
|
|
482
560
|
);
|
|
561
|
+
if (options.localOnly) {
|
|
562
|
+
await upsertLocalOnlyNotice(path6.join(cwd, AGENTS_FILE), result);
|
|
563
|
+
await upsertLocalOnlyNotice(path6.join(cwd, AGENTLOOP_FILE), result);
|
|
564
|
+
}
|
|
483
565
|
const configPath = path6.join(cwd, CONFIG_FILE);
|
|
484
566
|
if (await pathExists(configPath)) {
|
|
485
567
|
result.skipped.push(configPath);
|
|
@@ -502,29 +584,43 @@ var consoleLogger = {
|
|
|
502
584
|
|
|
503
585
|
// src/cli/commands/init.ts
|
|
504
586
|
function initCommand() {
|
|
505
|
-
return new Command("init").description("Initialize AgentLoopKit in the current repository").option("--dry-run", "show planned changes without writing files").option("--json", "print machine-readable output").option("--force", "allow initialization when the current directory is your home directory").
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
options.
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
consoleLogger.info(
|
|
524
|
-
consoleLogger.info(
|
|
525
|
-
consoleLogger.info(
|
|
587
|
+
return new Command("init").description("Initialize AgentLoopKit in the current repository").option("--dry-run", "show planned changes without writing files").option("--json", "print machine-readable output").option("--force", "allow initialization when the current directory is your home directory").option(
|
|
588
|
+
"--local-only",
|
|
589
|
+
"keep generated AgentLoopKit files out of git by updating this repo clone .git/info/exclude"
|
|
590
|
+
).action(
|
|
591
|
+
async (options) => {
|
|
592
|
+
const result = await initializeAgentLoop({
|
|
593
|
+
cwd: process.cwd(),
|
|
594
|
+
dryRun: options.dryRun,
|
|
595
|
+
force: options.force,
|
|
596
|
+
localOnly: options.localOnly
|
|
597
|
+
});
|
|
598
|
+
if (options.json) {
|
|
599
|
+
consoleLogger.info(JSON.stringify(result, null, 2));
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
consoleLogger.info(
|
|
603
|
+
options.dryRun ? "AgentLoopKit init dry run complete." : "AgentLoopKit initialized."
|
|
604
|
+
);
|
|
605
|
+
consoleLogger.info(`Created: ${result.created.length}`);
|
|
606
|
+
consoleLogger.info(`Updated: ${result.updated.length}`);
|
|
607
|
+
consoleLogger.info(`Skipped: ${result.skipped.length}`);
|
|
608
|
+
if (result.localOnly) {
|
|
609
|
+
consoleLogger.info("\nLocal-only mode:");
|
|
610
|
+
consoleLogger.info(`- Updated exclude file: ${result.localOnly.excludePath}`);
|
|
611
|
+
consoleLogger.info(
|
|
612
|
+
"- AgentLoopKit files stay on disk for local agents but stay out of git status."
|
|
613
|
+
);
|
|
614
|
+
consoleLogger.info("- Undo: remove the agentloopkit:local-only block from .git/info/exclude.");
|
|
615
|
+
}
|
|
616
|
+
if (!options.dryRun) {
|
|
617
|
+
consoleLogger.info("\nNext steps:");
|
|
618
|
+
consoleLogger.info("- Review AGENTS.md and AGENTLOOP.md");
|
|
619
|
+
consoleLogger.info("- Run agentloop doctor");
|
|
620
|
+
consoleLogger.info("- Create a task with agentloop create-task");
|
|
621
|
+
}
|
|
526
622
|
}
|
|
527
|
-
|
|
623
|
+
);
|
|
528
624
|
}
|
|
529
625
|
|
|
530
626
|
// src/cli/commands/doctor.ts
|
|
@@ -1268,7 +1364,7 @@ import { readFile as readFile8 } from "fs/promises";
|
|
|
1268
1364
|
|
|
1269
1365
|
// src/core/artifacts.ts
|
|
1270
1366
|
import path11 from "path";
|
|
1271
|
-
import { readdir as readdir4, stat as
|
|
1367
|
+
import { readdir as readdir4, stat as stat3 } from "fs/promises";
|
|
1272
1368
|
var verificationReportPattern = /^\d{4}-\d{2}-\d{2}-\d{2}-\d{2}-verification-report\.md$/;
|
|
1273
1369
|
var prSummaryPattern = /^\d{4}-\d{2}-\d{2}-\d{2}-\d{2}-pr-summary\.md$/;
|
|
1274
1370
|
var ciSummaryPattern = /^\d{4}-\d{2}-\d{2}-\d{2}-\d{2}-ci-summary\.md$/;
|
|
@@ -1279,7 +1375,7 @@ async function latestMarkdownFile(dir, options = {}) {
|
|
|
1279
1375
|
(entry) => entry.isFile() && entry.name.endsWith(".md") && entry.name.toLowerCase() !== "readme.md"
|
|
1280
1376
|
).filter((entry) => !options.pattern || options.pattern.test(entry.name)).map(async (entry) => {
|
|
1281
1377
|
const filePath = path11.join(dir, entry.name);
|
|
1282
|
-
const fileStat = await
|
|
1378
|
+
const fileStat = await stat3(filePath);
|
|
1283
1379
|
return { filePath, name: entry.name, mtimeMs: fileStat.mtimeMs };
|
|
1284
1380
|
})
|
|
1285
1381
|
);
|
|
@@ -1292,7 +1388,7 @@ async function latestMarkdownFile(dir, options = {}) {
|
|
|
1292
1388
|
|
|
1293
1389
|
// src/core/task-state.ts
|
|
1294
1390
|
import path12 from "path";
|
|
1295
|
-
import { mkdir as mkdir2, readdir as readdir5, readFile as readFile7, rename, rm, stat as
|
|
1391
|
+
import { mkdir as mkdir2, readdir as readdir5, readFile as readFile7, rename, rm, stat as stat4 } from "fs/promises";
|
|
1296
1392
|
var TASK_STATUSES = ["proposed", "in-progress", "blocked", "review", "done"];
|
|
1297
1393
|
function statePath(cwd, config) {
|
|
1298
1394
|
return path12.join(cwd, config.paths.agentloopDir, "state.json");
|
|
@@ -1337,7 +1433,7 @@ async function resolveTaskPath(options) {
|
|
|
1337
1433
|
if (!options.strict) return void 0;
|
|
1338
1434
|
throw new AgentLoopError("Active task must be a Markdown file.");
|
|
1339
1435
|
}
|
|
1340
|
-
const fileStat = await
|
|
1436
|
+
const fileStat = await stat4(absolutePath).catch(() => void 0);
|
|
1341
1437
|
if (!fileStat?.isFile()) {
|
|
1342
1438
|
if (!options.strict) return void 0;
|
|
1343
1439
|
throw new AgentLoopError(`Task contract not found: ${options.taskPath}`);
|
|
@@ -1444,7 +1540,7 @@ async function listTasks(options) {
|
|
|
1444
1540
|
const filePath = path12.join(root, entry.name);
|
|
1445
1541
|
const [metadata, fileStat] = await Promise.all([
|
|
1446
1542
|
readTaskMetadata(options.cwd, filePath),
|
|
1447
|
-
|
|
1543
|
+
stat4(filePath)
|
|
1448
1544
|
]);
|
|
1449
1545
|
return {
|
|
1450
1546
|
...metadata,
|
|
@@ -1776,7 +1872,7 @@ import { Command as Command9 } from "commander";
|
|
|
1776
1872
|
|
|
1777
1873
|
// src/core/status.ts
|
|
1778
1874
|
import path15 from "path";
|
|
1779
|
-
import { readFile as readFile9, stat as
|
|
1875
|
+
import { readFile as readFile9, stat as stat5 } from "fs/promises";
|
|
1780
1876
|
function extractHeading2(markdown, fallback) {
|
|
1781
1877
|
return markdown.match(/^#\s+(.+)$/m)?.[1]?.trim() || fallback;
|
|
1782
1878
|
}
|
|
@@ -1789,7 +1885,7 @@ function extractOverallStatus(markdown) {
|
|
|
1789
1885
|
async function readTask(cwd, filePath) {
|
|
1790
1886
|
if (!filePath) return void 0;
|
|
1791
1887
|
const markdown = await readFile9(filePath, "utf8");
|
|
1792
|
-
const fileStat = await
|
|
1888
|
+
const fileStat = await stat5(filePath);
|
|
1793
1889
|
return {
|
|
1794
1890
|
path: path15.relative(cwd, filePath),
|
|
1795
1891
|
title: extractHeading2(markdown, path15.basename(filePath, ".md")),
|
|
@@ -1800,7 +1896,7 @@ async function readTask(cwd, filePath) {
|
|
|
1800
1896
|
async function readReport(cwd, filePath) {
|
|
1801
1897
|
if (!filePath) return void 0;
|
|
1802
1898
|
const markdown = await readFile9(filePath, "utf8");
|
|
1803
|
-
const fileStat = await
|
|
1899
|
+
const fileStat = await stat5(filePath);
|
|
1804
1900
|
return {
|
|
1805
1901
|
path: path15.relative(cwd, filePath),
|
|
1806
1902
|
title: extractHeading2(markdown, path15.basename(filePath, ".md")),
|
|
@@ -2566,7 +2662,7 @@ import { Command as Command14 } from "commander";
|
|
|
2566
2662
|
|
|
2567
2663
|
// src/core/html-report.ts
|
|
2568
2664
|
import path17 from "path";
|
|
2569
|
-
import { readFile as readFile11, readdir as readdir6, stat as
|
|
2665
|
+
import { readFile as readFile11, readdir as readdir6, stat as stat6 } from "fs/promises";
|
|
2570
2666
|
function escapeHtml(value) {
|
|
2571
2667
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2572
2668
|
}
|
|
@@ -2598,7 +2694,7 @@ async function latestMatchingMarkdownFile(dir, pattern) {
|
|
|
2598
2694
|
const entries = await Promise.all(
|
|
2599
2695
|
(await readdir6(dir, { withFileTypes: true })).filter((entry) => entry.isFile() && pattern.test(entry.name)).map(async (entry) => {
|
|
2600
2696
|
const filePath = path17.join(dir, entry.name);
|
|
2601
|
-
const fileStat = await
|
|
2697
|
+
const fileStat = await stat6(filePath);
|
|
2602
2698
|
return { filePath, name: entry.name, mtimeMs: fileStat.mtimeMs };
|
|
2603
2699
|
})
|
|
2604
2700
|
);
|
|
@@ -2827,7 +2923,7 @@ import { Command as Command15 } from "commander";
|
|
|
2827
2923
|
|
|
2828
2924
|
// src/core/badge.ts
|
|
2829
2925
|
import path18 from "path";
|
|
2830
|
-
import { readFile as readFile12, readdir as readdir7, stat as
|
|
2926
|
+
import { readFile as readFile12, readdir as readdir7, stat as stat7 } from "fs/promises";
|
|
2831
2927
|
var verificationReportPattern2 = /^\d{4}-\d{2}-\d{2}-\d{2}-\d{2}-verification-report\.md$/;
|
|
2832
2928
|
function escapeXml(value) {
|
|
2833
2929
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -2858,7 +2954,7 @@ async function latestVerificationReport(dir) {
|
|
|
2858
2954
|
const entries = await Promise.all(
|
|
2859
2955
|
(await readdir7(dir, { withFileTypes: true })).filter((entry) => entry.isFile() && verificationReportPattern2.test(entry.name)).map(async (entry) => {
|
|
2860
2956
|
const filePath = path18.join(dir, entry.name);
|
|
2861
|
-
const fileStat = await
|
|
2957
|
+
const fileStat = await stat7(filePath);
|
|
2862
2958
|
return { filePath, name: entry.name, mtimeMs: fileStat.mtimeMs };
|
|
2863
2959
|
})
|
|
2864
2960
|
);
|
|
@@ -2996,7 +3092,7 @@ import { Command as Command16 } from "commander";
|
|
|
2996
3092
|
|
|
2997
3093
|
// src/core/policy.ts
|
|
2998
3094
|
import path19 from "path";
|
|
2999
|
-
import { readdir as readdir8, readFile as readFile13, stat as
|
|
3095
|
+
import { readdir as readdir8, readFile as readFile13, stat as stat8 } from "fs/promises";
|
|
3000
3096
|
function policyRoot(cwd, config) {
|
|
3001
3097
|
return path19.resolve(cwd, config.paths.agentloopDir, "policies");
|
|
3002
3098
|
}
|
|
@@ -3013,7 +3109,7 @@ function normalizeContent(content) {
|
|
|
3013
3109
|
return content.replace(/\r\n/g, "\n");
|
|
3014
3110
|
}
|
|
3015
3111
|
async function ensurePolicyRoot(root) {
|
|
3016
|
-
const rootStat = await
|
|
3112
|
+
const rootStat = await stat8(root).catch(() => void 0);
|
|
3017
3113
|
if (!rootStat?.isDirectory()) {
|
|
3018
3114
|
throw new AgentLoopError(
|
|
3019
3115
|
"No AgentLoopKit policy files found. Run `agentloop init` to generate .agentloop/policies/."
|