agentloopkit 0.25.0 → 0.26.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 +30 -4
- package/dist/cli/index.js +257 -2
- package/dist/cli/index.js.map +1 -1
- package/package.json +4 -1
- package/server.json +20 -0
package/README.md
CHANGED
|
@@ -60,8 +60,8 @@ npx agentloopkit init --local-only
|
|
|
60
60
|
Pin the current version when you need repeatable CI or team setup:
|
|
61
61
|
|
|
62
62
|
```bash
|
|
63
|
-
npx --yes agentloopkit@0.
|
|
64
|
-
npx --yes agentloopkit@0.
|
|
63
|
+
npx --yes agentloopkit@0.26.0 version
|
|
64
|
+
npx --yes agentloopkit@0.26.0 init
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
Run the CLI after install:
|
|
@@ -84,6 +84,7 @@ npx agentloopkit badge
|
|
|
84
84
|
npx agentloopkit ci-summary
|
|
85
85
|
npx agentloopkit release-notes
|
|
86
86
|
npx agentloopkit npm-status
|
|
87
|
+
npx agentloopkit mcp-server
|
|
87
88
|
npx agentloopkit policy list
|
|
88
89
|
npx agentloopkit policy show security
|
|
89
90
|
npx agentloopkit policy status
|
|
@@ -146,6 +147,7 @@ pnpm build
|
|
|
146
147
|
| `agentloop ci-summary` | Summarize CI context and local AgentLoop evidence |
|
|
147
148
|
| `agentloop release-notes` | Draft local release notes from changelog, git, task, and verification evidence |
|
|
148
149
|
| `agentloop npm-status` | Check npm registry status without publishing |
|
|
150
|
+
| `agentloop mcp-server` | Start a read-only MCP stdio server for local AgentLoopKit state |
|
|
149
151
|
| `agentloop policy list` | List local safety policy files |
|
|
150
152
|
| `agentloop policy show <policy>` | Print a local safety policy without mutating files |
|
|
151
153
|
| `agentloop policy status` | Compare local policy files with bundled templates |
|
|
@@ -393,7 +395,7 @@ See `docs/ci-summary.md`.
|
|
|
393
395
|
```bash
|
|
394
396
|
agentloop release-notes
|
|
395
397
|
agentloop release-notes --from v0.19.0 --to HEAD
|
|
396
|
-
agentloop release-notes --release-version 0.
|
|
398
|
+
agentloop release-notes --release-version 0.26.0
|
|
397
399
|
agentloop release-notes --json
|
|
398
400
|
agentloop release-notes --write
|
|
399
401
|
```
|
|
@@ -417,6 +419,18 @@ Use it after a publish attempt before saying npm has caught up. It runs `npm vie
|
|
|
417
419
|
|
|
418
420
|
See `docs/npm-status.md`.
|
|
419
421
|
|
|
422
|
+
## MCP Server
|
|
423
|
+
|
|
424
|
+
AgentLoopKit can expose existing repo evidence to MCP clients through a read-only stdio server:
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
npx --yes agentloopkit@0.26.0 mcp-server
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
The server provides tools for status, next action, task contracts, active task, policies, latest verification report, and handoff summaries. It does not run verification commands, edit files, call external APIs, read `.env` contents, or upload data.
|
|
431
|
+
|
|
432
|
+
See `docs/mcp.md` for client configuration, tool names, and registry notes.
|
|
433
|
+
|
|
420
434
|
<p align="center">
|
|
421
435
|
<img src="https://raw.githubusercontent.com/abhiyoheswaran1/AgentLoopKit/main/docs/assets/readme/agentloopkit-verification.png" alt="AgentLoopKit verification report screenshot showing task context, passing command results, and reviewer handoff sections" width="100%">
|
|
422
436
|
</p>
|
|
@@ -459,7 +473,19 @@ Use `agentloop check-gates --strict` as a review-evidence gate in pull request C
|
|
|
459
473
|
|
|
460
474
|
CI-generated verification reports include GitHub Actions provenance when available, so reviewers can trace an artifact back to the workflow run that created it.
|
|
461
475
|
|
|
462
|
-
See `docs/github-actions.md`, `examples/github-actions/`, `examples/gitlab-ci/`, and `examples/buildkite/` for copy-pasteable workflows. Pin `agentloopkit@0.
|
|
476
|
+
See `docs/github-actions.md`, `examples/github-actions/`, `examples/gitlab-ci/`, and `examples/buildkite/` for copy-pasteable workflows. Pin `agentloopkit@0.26.0` or a newer vetted release when reproducibility matters.
|
|
477
|
+
|
|
478
|
+
## Other Install Channels
|
|
479
|
+
|
|
480
|
+
npm and npx remain the primary install path. AgentLoopKit also ships release assets and maintainer artifacts for:
|
|
481
|
+
|
|
482
|
+
- GitHub Releases: versioned tarballs for provenance and rollback.
|
|
483
|
+
- GitHub Action: a thin wrapper for `agentloop` commands in CI.
|
|
484
|
+
- Docker/GHCR: a minimal image that runs `agentloop`.
|
|
485
|
+
- Homebrew: a formula under `packaging/homebrew/` for the tap release flow.
|
|
486
|
+
- MCP Registry: read-only server metadata for MCP clients once the matching npm package is published.
|
|
487
|
+
|
|
488
|
+
See `docs/distribution-channels.md` for current commands and maintainer release steps.
|
|
463
489
|
|
|
464
490
|
## PR Summaries
|
|
465
491
|
|
package/dist/cli/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command21 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/cli/commands/init.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -2210,6 +2210,7 @@ var topLevelCommands = [
|
|
|
2210
2210
|
["ci-summary", "Summarize CI context and AgentLoop evidence"],
|
|
2211
2211
|
["release-notes", "Generate deterministic release notes"],
|
|
2212
2212
|
["npm-status", "Check npm registry catch-up status"],
|
|
2213
|
+
["mcp-server", "Start the read-only MCP stdio server"],
|
|
2213
2214
|
["policy", "List or inspect local AgentLoopKit policies"],
|
|
2214
2215
|
["task", "List, inspect, update, or archive task contracts"],
|
|
2215
2216
|
["install-agent", "Install agent-specific instructions"],
|
|
@@ -3902,8 +3903,261 @@ function npmStatusCommand() {
|
|
|
3902
3903
|
);
|
|
3903
3904
|
}
|
|
3904
3905
|
|
|
3906
|
+
// src/cli/commands/mcp-server.ts
|
|
3907
|
+
import { Command as Command20 } from "commander";
|
|
3908
|
+
|
|
3909
|
+
// src/mcp/server.ts
|
|
3910
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3911
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3912
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
3913
|
+
|
|
3914
|
+
// src/core/mcp-tools.ts
|
|
3915
|
+
import path23 from "path";
|
|
3916
|
+
import { readdir as readdir9, readFile as readFile18, stat as stat9 } from "fs/promises";
|
|
3917
|
+
var emptyInputSchema = {
|
|
3918
|
+
type: "object",
|
|
3919
|
+
properties: {},
|
|
3920
|
+
additionalProperties: false
|
|
3921
|
+
};
|
|
3922
|
+
var tools = [
|
|
3923
|
+
{
|
|
3924
|
+
name: "agentloop_status",
|
|
3925
|
+
description: "Read AgentLoopKit status, active task, latest verification, git state, and next action.",
|
|
3926
|
+
inputSchema: emptyInputSchema
|
|
3927
|
+
},
|
|
3928
|
+
{
|
|
3929
|
+
name: "agentloop_next",
|
|
3930
|
+
description: "Read only the next recommended AgentLoopKit action and reason.",
|
|
3931
|
+
inputSchema: emptyInputSchema
|
|
3932
|
+
},
|
|
3933
|
+
{
|
|
3934
|
+
name: "agentloop_list_tasks",
|
|
3935
|
+
description: "List local task contracts under the configured AgentLoopKit task directory.",
|
|
3936
|
+
inputSchema: emptyInputSchema
|
|
3937
|
+
},
|
|
3938
|
+
{
|
|
3939
|
+
name: "agentloop_show_active_task",
|
|
3940
|
+
description: "Read the active task contract content when one is pinned.",
|
|
3941
|
+
inputSchema: emptyInputSchema
|
|
3942
|
+
},
|
|
3943
|
+
{
|
|
3944
|
+
name: "agentloop_list_policies",
|
|
3945
|
+
description: "List local AgentLoopKit safety policy files.",
|
|
3946
|
+
inputSchema: emptyInputSchema
|
|
3947
|
+
},
|
|
3948
|
+
{
|
|
3949
|
+
name: "agentloop_read_policy",
|
|
3950
|
+
description: "Read one local AgentLoopKit policy by policy name.",
|
|
3951
|
+
inputSchema: {
|
|
3952
|
+
type: "object",
|
|
3953
|
+
properties: {
|
|
3954
|
+
policyName: {
|
|
3955
|
+
type: "string",
|
|
3956
|
+
description: 'Policy name, for example "security" or "security-policy.md".'
|
|
3957
|
+
}
|
|
3958
|
+
},
|
|
3959
|
+
required: ["policyName"],
|
|
3960
|
+
additionalProperties: false
|
|
3961
|
+
}
|
|
3962
|
+
},
|
|
3963
|
+
{
|
|
3964
|
+
name: "agentloop_latest_verification_report",
|
|
3965
|
+
description: "Read the latest local verification report metadata and Markdown content.",
|
|
3966
|
+
inputSchema: emptyInputSchema
|
|
3967
|
+
},
|
|
3968
|
+
{
|
|
3969
|
+
name: "agentloop_list_handoffs",
|
|
3970
|
+
description: "List recent local reviewer handoff summaries.",
|
|
3971
|
+
inputSchema: {
|
|
3972
|
+
type: "object",
|
|
3973
|
+
properties: {
|
|
3974
|
+
limit: {
|
|
3975
|
+
type: "number",
|
|
3976
|
+
minimum: 1,
|
|
3977
|
+
maximum: 50,
|
|
3978
|
+
description: "Maximum handoff summaries to return. Defaults to 20."
|
|
3979
|
+
}
|
|
3980
|
+
},
|
|
3981
|
+
additionalProperties: false
|
|
3982
|
+
}
|
|
3983
|
+
},
|
|
3984
|
+
{
|
|
3985
|
+
name: "agentloop_latest_handoff",
|
|
3986
|
+
description: "Read the latest local reviewer handoff summary Markdown content.",
|
|
3987
|
+
inputSchema: emptyInputSchema
|
|
3988
|
+
}
|
|
3989
|
+
];
|
|
3990
|
+
function listMcpTools() {
|
|
3991
|
+
return [...tools];
|
|
3992
|
+
}
|
|
3993
|
+
function textResult(payload) {
|
|
3994
|
+
return {
|
|
3995
|
+
payload,
|
|
3996
|
+
content: [
|
|
3997
|
+
{
|
|
3998
|
+
type: "text",
|
|
3999
|
+
text: JSON.stringify(payload, null, 2)
|
|
4000
|
+
}
|
|
4001
|
+
]
|
|
4002
|
+
};
|
|
4003
|
+
}
|
|
4004
|
+
function extractHeading7(markdown, fallback) {
|
|
4005
|
+
return markdown.match(/^#\s+(.+)$/m)?.[1]?.trim() || fallback;
|
|
4006
|
+
}
|
|
4007
|
+
function toStoredPath3(cwd, absolutePath) {
|
|
4008
|
+
return path23.relative(cwd, absolutePath).split(path23.sep).join("/");
|
|
4009
|
+
}
|
|
4010
|
+
async function readMarkdownArtifact(cwd, filePath, key) {
|
|
4011
|
+
if (!filePath) return { [key]: null };
|
|
4012
|
+
const content = await readFile18(filePath, "utf8");
|
|
4013
|
+
const fileStat = await stat9(filePath);
|
|
4014
|
+
return {
|
|
4015
|
+
[key]: {
|
|
4016
|
+
path: toStoredPath3(cwd, filePath),
|
|
4017
|
+
title: extractHeading7(content, path23.basename(filePath, ".md")),
|
|
4018
|
+
modifiedAt: fileStat.mtime.toISOString(),
|
|
4019
|
+
content
|
|
4020
|
+
}
|
|
4021
|
+
};
|
|
4022
|
+
}
|
|
4023
|
+
async function listHandoffs(cwd, handoffsDir, limit) {
|
|
4024
|
+
if (!await pathExists(handoffsDir)) return [];
|
|
4025
|
+
const entries = await readdir9(handoffsDir, { withFileTypes: true });
|
|
4026
|
+
const handoffs = await Promise.all(
|
|
4027
|
+
entries.filter((entry) => entry.isFile() && prSummaryPattern.test(entry.name)).map(async (entry) => {
|
|
4028
|
+
const filePath = path23.join(handoffsDir, entry.name);
|
|
4029
|
+
const [content, fileStat] = await Promise.all([readFile18(filePath, "utf8"), stat9(filePath)]);
|
|
4030
|
+
return {
|
|
4031
|
+
path: toStoredPath3(cwd, filePath),
|
|
4032
|
+
title: extractHeading7(content, path23.basename(filePath, ".md")),
|
|
4033
|
+
modifiedAt: fileStat.mtime.toISOString(),
|
|
4034
|
+
modifiedMs: fileStat.mtimeMs
|
|
4035
|
+
};
|
|
4036
|
+
})
|
|
4037
|
+
);
|
|
4038
|
+
return handoffs.sort((left, right) => {
|
|
4039
|
+
if (left.modifiedMs !== right.modifiedMs) return right.modifiedMs - left.modifiedMs;
|
|
4040
|
+
return left.path.localeCompare(right.path);
|
|
4041
|
+
}).slice(0, limit).map((handoff) => ({
|
|
4042
|
+
path: handoff.path,
|
|
4043
|
+
title: handoff.title,
|
|
4044
|
+
modifiedAt: handoff.modifiedAt
|
|
4045
|
+
}));
|
|
4046
|
+
}
|
|
4047
|
+
function readStringArgument(args, key) {
|
|
4048
|
+
const value = args?.[key];
|
|
4049
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
4050
|
+
throw new AgentLoopError(`MCP tool argument "${key}" must be a non-empty string.`);
|
|
4051
|
+
}
|
|
4052
|
+
return value;
|
|
4053
|
+
}
|
|
4054
|
+
function readLimitArgument(args) {
|
|
4055
|
+
const value = args?.limit;
|
|
4056
|
+
if (value === void 0) return 20;
|
|
4057
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 1 || value > 50) {
|
|
4058
|
+
throw new AgentLoopError('MCP tool argument "limit" must be an integer from 1 to 50.');
|
|
4059
|
+
}
|
|
4060
|
+
return value;
|
|
4061
|
+
}
|
|
4062
|
+
async function callMcpTool(options) {
|
|
4063
|
+
const config = await loadAgentLoopConfig(options.cwd);
|
|
4064
|
+
switch (options.name) {
|
|
4065
|
+
case "agentloop_status": {
|
|
4066
|
+
const status = await getAgentLoopStatus({ cwd: options.cwd, config });
|
|
4067
|
+
return textResult(status);
|
|
4068
|
+
}
|
|
4069
|
+
case "agentloop_next": {
|
|
4070
|
+
const status = await getAgentLoopStatus({ cwd: options.cwd, config });
|
|
4071
|
+
return textResult(status.nextAction);
|
|
4072
|
+
}
|
|
4073
|
+
case "agentloop_list_tasks": {
|
|
4074
|
+
return textResult({ tasks: await listTasks({ cwd: options.cwd, config }) });
|
|
4075
|
+
}
|
|
4076
|
+
case "agentloop_show_active_task": {
|
|
4077
|
+
const activeTask = await getActiveTask({ cwd: options.cwd, config });
|
|
4078
|
+
if (!activeTask) return textResult({ task: null });
|
|
4079
|
+
const task = await readTaskContract({ cwd: options.cwd, config, taskPath: activeTask.path });
|
|
4080
|
+
return textResult({ task });
|
|
4081
|
+
}
|
|
4082
|
+
case "agentloop_list_policies": {
|
|
4083
|
+
return textResult({ policies: await listPolicies({ cwd: options.cwd, config }) });
|
|
4084
|
+
}
|
|
4085
|
+
case "agentloop_read_policy": {
|
|
4086
|
+
const policyName = readStringArgument(options.arguments, "policyName");
|
|
4087
|
+
return textResult({
|
|
4088
|
+
policy: await readPolicy({ cwd: options.cwd, config, policyName })
|
|
4089
|
+
});
|
|
4090
|
+
}
|
|
4091
|
+
case "agentloop_latest_verification_report": {
|
|
4092
|
+
const reportPath = await latestMarkdownFile(
|
|
4093
|
+
path23.join(options.cwd, config.paths.reportsDir),
|
|
4094
|
+
{
|
|
4095
|
+
pattern: verificationReportPattern
|
|
4096
|
+
}
|
|
4097
|
+
);
|
|
4098
|
+
return textResult(await readMarkdownArtifact(options.cwd, reportPath, "report"));
|
|
4099
|
+
}
|
|
4100
|
+
case "agentloop_list_handoffs": {
|
|
4101
|
+
const limit = readLimitArgument(options.arguments);
|
|
4102
|
+
return textResult({
|
|
4103
|
+
handoffs: await listHandoffs(
|
|
4104
|
+
options.cwd,
|
|
4105
|
+
path23.join(options.cwd, config.paths.handoffsDir),
|
|
4106
|
+
limit
|
|
4107
|
+
)
|
|
4108
|
+
});
|
|
4109
|
+
}
|
|
4110
|
+
case "agentloop_latest_handoff": {
|
|
4111
|
+
const handoffPath = await latestMarkdownFile(
|
|
4112
|
+
path23.join(options.cwd, config.paths.handoffsDir),
|
|
4113
|
+
{
|
|
4114
|
+
pattern: prSummaryPattern
|
|
4115
|
+
}
|
|
4116
|
+
);
|
|
4117
|
+
return textResult(await readMarkdownArtifact(options.cwd, handoffPath, "handoff"));
|
|
4118
|
+
}
|
|
4119
|
+
default:
|
|
4120
|
+
throw new AgentLoopError(`Unknown MCP tool: ${options.name}`);
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4123
|
+
|
|
4124
|
+
// src/mcp/server.ts
|
|
4125
|
+
async function startAgentLoopMcpServer(options) {
|
|
4126
|
+
const server = new Server(
|
|
4127
|
+
{
|
|
4128
|
+
name: "agentloopkit",
|
|
4129
|
+
version: getPackageVersion()
|
|
4130
|
+
},
|
|
4131
|
+
{
|
|
4132
|
+
capabilities: {
|
|
4133
|
+
tools: {}
|
|
4134
|
+
},
|
|
4135
|
+
instructions: "Read-only AgentLoopKit server. Exposes local task contracts, policies, verification reports, handoffs, status, and next action. It does not run verification commands, read env file contents, call external APIs, upload files, or mutate repository files."
|
|
4136
|
+
}
|
|
4137
|
+
);
|
|
4138
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
4139
|
+
tools: listMcpTools()
|
|
4140
|
+
}));
|
|
4141
|
+
server.setRequestHandler(
|
|
4142
|
+
CallToolRequestSchema,
|
|
4143
|
+
async (request) => callMcpTool({
|
|
4144
|
+
cwd: options.cwd,
|
|
4145
|
+
name: request.params.name,
|
|
4146
|
+
arguments: request.params.arguments
|
|
4147
|
+
})
|
|
4148
|
+
);
|
|
4149
|
+
await server.connect(new StdioServerTransport());
|
|
4150
|
+
}
|
|
4151
|
+
|
|
4152
|
+
// src/cli/commands/mcp-server.ts
|
|
4153
|
+
function mcpServerCommand() {
|
|
4154
|
+
return new Command20("mcp-server").description("Start the read-only AgentLoopKit MCP stdio server").action(async () => {
|
|
4155
|
+
await startAgentLoopMcpServer({ cwd: process.cwd() });
|
|
4156
|
+
});
|
|
4157
|
+
}
|
|
4158
|
+
|
|
3905
4159
|
// src/cli/index.ts
|
|
3906
|
-
var program = new
|
|
4160
|
+
var program = new Command21();
|
|
3907
4161
|
program.name("agentloop").description("A drop-in engineering loop for coding agents.").version(getPackageVersion(), "-V, --version", "print CLI version");
|
|
3908
4162
|
program.addCommand(initCommand());
|
|
3909
4163
|
program.addCommand(doctorCommand());
|
|
@@ -3919,6 +4173,7 @@ program.addCommand(badgeCommand());
|
|
|
3919
4173
|
program.addCommand(ciSummaryCommand());
|
|
3920
4174
|
program.addCommand(releaseNotesCommand());
|
|
3921
4175
|
program.addCommand(npmStatusCommand());
|
|
4176
|
+
program.addCommand(mcpServerCommand());
|
|
3922
4177
|
program.addCommand(policyCommand());
|
|
3923
4178
|
program.addCommand(taskCommand());
|
|
3924
4179
|
program.addCommand(installAgentCommand());
|