agentpack-cli 0.1.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/LICENSE +21 -0
- package/README.md +174 -0
- package/SECURITY.md +44 -0
- package/assets/agentpack-logo.jpg +0 -0
- package/dist/src/agentpack.d.ts +2 -0
- package/dist/src/agentpack.js +8 -0
- package/dist/src/agentpack.js.map +1 -0
- package/dist/src/cli/index.d.ts +3 -0
- package/dist/src/cli/index.js +412 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/core/budget.d.ts +14 -0
- package/dist/src/core/budget.js +56 -0
- package/dist/src/core/budget.js.map +1 -0
- package/dist/src/core/checkpoints.d.ts +24 -0
- package/dist/src/core/checkpoints.js +93 -0
- package/dist/src/core/checkpoints.js.map +1 -0
- package/dist/src/core/doctor.d.ts +4 -0
- package/dist/src/core/doctor.js +304 -0
- package/dist/src/core/doctor.js.map +1 -0
- package/dist/src/core/git.d.ts +2 -0
- package/dist/src/core/git.js +34 -0
- package/dist/src/core/git.js.map +1 -0
- package/dist/src/core/hash.d.ts +5 -0
- package/dist/src/core/hash.js +29 -0
- package/dist/src/core/hash.js.map +1 -0
- package/dist/src/core/ids.d.ts +1 -0
- package/dist/src/core/ids.js +7 -0
- package/dist/src/core/ids.js.map +1 -0
- package/dist/src/core/presets.d.ts +12 -0
- package/dist/src/core/presets.js +24 -0
- package/dist/src/core/presets.js.map +1 -0
- package/dist/src/core/redaction.d.ts +4 -0
- package/dist/src/core/redaction.js +18 -0
- package/dist/src/core/redaction.js.map +1 -0
- package/dist/src/core/resume.d.ts +13 -0
- package/dist/src/core/resume.js +398 -0
- package/dist/src/core/resume.js.map +1 -0
- package/dist/src/core/store.d.ts +20 -0
- package/dist/src/core/store.js +240 -0
- package/dist/src/core/store.js.map +1 -0
- package/dist/src/core/types.d.ts +43 -0
- package/dist/src/core/types.js +2 -0
- package/dist/src/core/types.js.map +1 -0
- package/dist/src/integrations/install.d.ts +5 -0
- package/dist/src/integrations/install.js +361 -0
- package/dist/src/integrations/install.js.map +1 -0
- package/dist/src/mcp/server.d.ts +9 -0
- package/dist/src/mcp/server.js +347 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/operations.d.ts +29 -0
- package/dist/src/operations.js +199 -0
- package/dist/src/operations.js.map +1 -0
- package/docs/DOGFOOD.md +72 -0
- package/docs/INTEGRATIONS.md +183 -0
- package/docs/MCP.md +83 -0
- package/docs/MVP.md +97 -0
- package/docs/ROADMAP.md +129 -0
- package/docs/SETUP.md +56 -0
- package/docs/agentpack-flow.md +63 -0
- package/package.json +55 -0
- package/scripts/mcp-smoke.mjs +197 -0
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agentpack-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local task-state ledger for AI coding agents.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/ihorponom/agentpack.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/ihorponom/agentpack#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/ihorponom/agentpack/issues"
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"agentpack": "./dist/src/agentpack.js"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc -p tsconfig.json",
|
|
19
|
+
"mcp:smoke": "npm run build && node scripts/mcp-smoke.mjs",
|
|
20
|
+
"smoke": "npm run build && node dist/src/agentpack.js --help",
|
|
21
|
+
"test": "npm run build && node --test dist/tests/*.test.js",
|
|
22
|
+
"prepack": "npm test"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=20"
|
|
26
|
+
},
|
|
27
|
+
"packageManager": "npm@10.9.7",
|
|
28
|
+
"keywords": [
|
|
29
|
+
"agents",
|
|
30
|
+
"ai",
|
|
31
|
+
"coding-agents",
|
|
32
|
+
"agent-state",
|
|
33
|
+
"agent-memory",
|
|
34
|
+
"mcp",
|
|
35
|
+
"local-first"
|
|
36
|
+
],
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"files": [
|
|
39
|
+
"dist/src",
|
|
40
|
+
"scripts/mcp-smoke.mjs",
|
|
41
|
+
"docs",
|
|
42
|
+
"README.md",
|
|
43
|
+
"SECURITY.md",
|
|
44
|
+
"LICENSE",
|
|
45
|
+
"assets/agentpack-logo.jpg"
|
|
46
|
+
],
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public",
|
|
49
|
+
"provenance": true
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/node": "22.15.3",
|
|
53
|
+
"typescript": "5.8.3"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
4
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
10
|
+
const cliPath = path.join(repoRoot, "dist", "src", "agentpack.js");
|
|
11
|
+
const workspace = mkdtempSync(path.join(tmpdir(), "agentpack-mcp-smoke-"));
|
|
12
|
+
|
|
13
|
+
let server;
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
writeFileSync(path.join(workspace, "index.js"), "console.log('agentpack mcp smoke')\n", "utf8");
|
|
17
|
+
runCli(["init"]);
|
|
18
|
+
runCli(["set", "goal", "Exercise Agentpack MCP smoke flow."]);
|
|
19
|
+
|
|
20
|
+
server = spawn(process.execPath, [cliPath, "mcp", "--root", workspace], {
|
|
21
|
+
cwd: repoRoot,
|
|
22
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const client = createJsonRpcClient(server);
|
|
26
|
+
|
|
27
|
+
const initialize = await client.request("initialize", {});
|
|
28
|
+
assertEqual(initialize.result?.serverInfo?.name, "agentpack", "initialize returned the Agentpack server name");
|
|
29
|
+
|
|
30
|
+
const toolsResponse = await client.request("tools/list", {});
|
|
31
|
+
const toolNames = toolsResponse.result?.tools?.map((tool) => tool.name).sort() || [];
|
|
32
|
+
for (const expected of ["load_context", "record_decision", "record_source", "resume", "source_status"]) {
|
|
33
|
+
assertIncludes(toolNames, expected, `tools/list includes ${expected}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
await client.request("tools/call", {
|
|
37
|
+
name: "record_decision",
|
|
38
|
+
arguments: {
|
|
39
|
+
text: "MCP smoke can record decisions.",
|
|
40
|
+
files: ["index.js"]
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
await client.request("tools/call", {
|
|
45
|
+
name: "record_source",
|
|
46
|
+
arguments: {
|
|
47
|
+
path: "index.js",
|
|
48
|
+
summary: "Temporary smoke source inspected through MCP."
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const sourceStatus = await client.request("tools/call", {
|
|
53
|
+
name: "source_status",
|
|
54
|
+
arguments: {}
|
|
55
|
+
});
|
|
56
|
+
assertMatch(sourceStatus.result?.content?.[0]?.text || "", /UNCHANGED index\.js/, "source_status reports unchanged source");
|
|
57
|
+
|
|
58
|
+
const resume = await client.request("tools/call", {
|
|
59
|
+
name: "resume",
|
|
60
|
+
arguments: {
|
|
61
|
+
preset: "quick"
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
const resumeText = resume.result?.content?.[0]?.text || "";
|
|
65
|
+
assertMatch(resumeText, /Exercise Agentpack MCP smoke flow/, "resume contains the smoke goal");
|
|
66
|
+
assertMatch(resumeText, /MCP smoke can record decisions/, "resume contains the MCP decision");
|
|
67
|
+
|
|
68
|
+
console.log("MCP server OK");
|
|
69
|
+
console.log(`Tools: ${toolNames.join(", ")}`);
|
|
70
|
+
console.log("Flow: initialize -> tools/list -> record_decision -> record_source -> source_status -> resume");
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error("MCP smoke failed");
|
|
73
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
74
|
+
process.exitCode = 1;
|
|
75
|
+
} finally {
|
|
76
|
+
if (server) {
|
|
77
|
+
await stopServer(server);
|
|
78
|
+
}
|
|
79
|
+
rmSync(workspace, { recursive: true, force: true });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function runCli(args) {
|
|
83
|
+
execFileSync(process.execPath, [cliPath, ...args], {
|
|
84
|
+
cwd: workspace,
|
|
85
|
+
stdio: "pipe"
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function createJsonRpcClient(child) {
|
|
90
|
+
let nextId = 1;
|
|
91
|
+
let buffer = "";
|
|
92
|
+
let stderr = "";
|
|
93
|
+
const pending = new Map();
|
|
94
|
+
|
|
95
|
+
child.stdout.setEncoding("utf8");
|
|
96
|
+
child.stdout.on("data", (chunk) => {
|
|
97
|
+
buffer += chunk;
|
|
98
|
+
const lines = buffer.split("\n");
|
|
99
|
+
buffer = lines.pop() || "";
|
|
100
|
+
|
|
101
|
+
for (const line of lines) {
|
|
102
|
+
if (!line.trim()) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const message = JSON.parse(line);
|
|
107
|
+
const waiter = pending.get(message.id);
|
|
108
|
+
if (waiter) {
|
|
109
|
+
pending.delete(message.id);
|
|
110
|
+
waiter.resolve(message);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
child.stderr.setEncoding("utf8");
|
|
116
|
+
child.stderr.on("data", (chunk) => {
|
|
117
|
+
stderr += chunk;
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
child.on("exit", (code, signal) => {
|
|
121
|
+
for (const [id, waiter] of pending) {
|
|
122
|
+
pending.delete(id);
|
|
123
|
+
waiter.reject(new Error(`MCP server exited before response ${id}; code=${code}, signal=${signal}, stderr=${stderr.trim()}`));
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
request(method, params) {
|
|
129
|
+
const id = nextId;
|
|
130
|
+
nextId += 1;
|
|
131
|
+
|
|
132
|
+
const promise = new Promise((resolve, reject) => {
|
|
133
|
+
const timer = setTimeout(() => {
|
|
134
|
+
pending.delete(id);
|
|
135
|
+
reject(new Error(`Timed out waiting for MCP response ${id}; stderr=${stderr.trim()}`));
|
|
136
|
+
}, 2000);
|
|
137
|
+
|
|
138
|
+
pending.set(id, {
|
|
139
|
+
resolve(message) {
|
|
140
|
+
clearTimeout(timer);
|
|
141
|
+
if (message.error) {
|
|
142
|
+
reject(new Error(`${method} failed: ${message.error.message}`));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
resolve(message);
|
|
146
|
+
},
|
|
147
|
+
reject(error) {
|
|
148
|
+
clearTimeout(timer);
|
|
149
|
+
reject(error);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id, method, params })}\n`);
|
|
155
|
+
return promise;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function stopServer(child) {
|
|
161
|
+
return new Promise((resolve) => {
|
|
162
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
163
|
+
resolve();
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
let done = false;
|
|
168
|
+
const finish = () => {
|
|
169
|
+
if (!done) {
|
|
170
|
+
done = true;
|
|
171
|
+
resolve();
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
child.once("exit", finish);
|
|
176
|
+
child.kill();
|
|
177
|
+
setTimeout(finish, 500).unref();
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function assertEqual(actual, expected, message) {
|
|
182
|
+
if (actual !== expected) {
|
|
183
|
+
throw new Error(`${message}: expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function assertIncludes(values, expected, message) {
|
|
188
|
+
if (!values.includes(expected)) {
|
|
189
|
+
throw new Error(`${message}: missing ${expected}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function assertMatch(value, pattern, message) {
|
|
194
|
+
if (!pattern.test(value)) {
|
|
195
|
+
throw new Error(`${message}: ${pattern} did not match`);
|
|
196
|
+
}
|
|
197
|
+
}
|