@iinm/plain-agent 1.8.1 → 1.8.3
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 +4 -0
- package/package.json +7 -7
- package/src/cliBatch.mjs +3 -0
- package/src/cliInteractive.mjs +6 -3
- package/src/context/loadAgentRoles.mjs +2 -2
- package/src/context/loadPrompts.mjs +2 -2
- package/src/main.mjs +1 -0
- package/src/providers/platform/googleCloud.mjs +1 -1
- package/src/mcpClient.test.mockServer.mjs +0 -83
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iinm/plain-agent",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.3",
|
|
4
4
|
"description": "A lightweight CLI-based coding agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"url": "git+https://github.com/iinm/plain-agent.git"
|
|
10
10
|
},
|
|
11
11
|
"bin": {
|
|
12
|
-
"plain": "
|
|
13
|
-
"plain-notify-desktop": "
|
|
14
|
-
"plain-sandbox": "
|
|
12
|
+
"plain": "bin/plain",
|
|
13
|
+
"plain-notify-desktop": "bin/plain-notify-desktop",
|
|
14
|
+
"plain-sandbox": "sandbox/bin/plain-sandbox"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"bin",
|
|
@@ -20,8 +20,9 @@
|
|
|
20
20
|
"src/**/*.mjs",
|
|
21
21
|
"src/**/*.d.ts",
|
|
22
22
|
"!src/**/*.test.mjs",
|
|
23
|
+
"!src/**/*.test.*.mjs",
|
|
23
24
|
"!src/**/*.playground.mjs",
|
|
24
|
-
"!src
|
|
25
|
+
"!src/**/test/"
|
|
25
26
|
],
|
|
26
27
|
"engines": {
|
|
27
28
|
"node": ">=22"
|
|
@@ -34,11 +35,10 @@
|
|
|
34
35
|
},
|
|
35
36
|
"dependencies": {
|
|
36
37
|
"diff": "^8.0.4",
|
|
37
|
-
"
|
|
38
|
+
"yaml": "^2.8.3"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@biomejs/biome": "^2.4.12",
|
|
41
|
-
"@types/js-yaml": "^4.0.9",
|
|
42
42
|
"@types/node": "^22.19.17",
|
|
43
43
|
"typescript": "^6.0.2"
|
|
44
44
|
}
|
package/src/cliBatch.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import { appendUsageRecord, buildUsageRecord } from "./usageStore.mjs";
|
|
|
14
14
|
* @property {string} sessionId
|
|
15
15
|
* @property {string} modelName
|
|
16
16
|
* @property {boolean} sandbox
|
|
17
|
+
* @property {Date} startTime
|
|
17
18
|
* @property {() => Promise<void>} onStop
|
|
18
19
|
*/
|
|
19
20
|
|
|
@@ -32,6 +33,7 @@ export async function startBatchSession({
|
|
|
32
33
|
sessionId,
|
|
33
34
|
modelName,
|
|
34
35
|
sandbox,
|
|
36
|
+
startTime,
|
|
35
37
|
onStop,
|
|
36
38
|
}) {
|
|
37
39
|
setupEventHandlers(agentEventEmitter, { sessionId, modelName, sandbox });
|
|
@@ -55,6 +57,7 @@ export async function startBatchSession({
|
|
|
55
57
|
modelName,
|
|
56
58
|
workingDir: process.cwd(),
|
|
57
59
|
costSummary,
|
|
60
|
+
now: startTime,
|
|
58
61
|
});
|
|
59
62
|
if (record) {
|
|
60
63
|
await appendUsageRecord(record);
|
package/src/cliInteractive.mjs
CHANGED
|
@@ -57,6 +57,7 @@ const HELP_MESSAGE = [
|
|
|
57
57
|
* @property {AgentCommands} agentCommands
|
|
58
58
|
* @property {string} sessionId
|
|
59
59
|
* @property {string} modelName
|
|
60
|
+
* @property {Date} startTime
|
|
60
61
|
* @property {{ command: string; args?: string[] } | undefined} notifyCmd
|
|
61
62
|
* @property {boolean} sandbox
|
|
62
63
|
* @property {() => Promise<void>} onStop
|
|
@@ -69,9 +70,9 @@ const HELP_MESSAGE = [
|
|
|
69
70
|
* Failures are logged but never thrown so exit is not blocked.
|
|
70
71
|
*
|
|
71
72
|
* @param {import("./costTracker.mjs").CostSummary} summary
|
|
72
|
-
* @param {{ sessionId: string, modelName: string }} meta
|
|
73
|
+
* @param {{ sessionId: string, modelName: string, startTime: Date }} meta
|
|
73
74
|
*/
|
|
74
|
-
async function persistUsage(summary, { sessionId, modelName }) {
|
|
75
|
+
async function persistUsage(summary, { sessionId, modelName, startTime }) {
|
|
75
76
|
try {
|
|
76
77
|
const record = buildUsageRecord({
|
|
77
78
|
sessionId,
|
|
@@ -79,6 +80,7 @@ async function persistUsage(summary, { sessionId, modelName }) {
|
|
|
79
80
|
modelName,
|
|
80
81
|
workingDir: process.cwd(),
|
|
81
82
|
costSummary: summary,
|
|
83
|
+
now: startTime,
|
|
82
84
|
});
|
|
83
85
|
if (!record) return;
|
|
84
86
|
await appendUsageRecord(record);
|
|
@@ -99,6 +101,7 @@ export function startInteractiveSession({
|
|
|
99
101
|
agentCommands,
|
|
100
102
|
sessionId,
|
|
101
103
|
modelName,
|
|
104
|
+
startTime,
|
|
102
105
|
notifyCmd,
|
|
103
106
|
sandbox,
|
|
104
107
|
onStop,
|
|
@@ -153,7 +156,7 @@ export function startInteractiveSession({
|
|
|
153
156
|
const summary = agentCommands.getCostSummary();
|
|
154
157
|
console.log();
|
|
155
158
|
console.log(formatCostSummary(summary));
|
|
156
|
-
await persistUsage(summary, { sessionId, modelName });
|
|
159
|
+
await persistUsage(summary, { sessionId, modelName, startTime });
|
|
157
160
|
await onStop();
|
|
158
161
|
process.exit(0);
|
|
159
162
|
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import crypto from "node:crypto";
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import
|
|
6
|
+
import { parse as parseYaml } from "yaml";
|
|
7
7
|
import {
|
|
8
8
|
AGENT_CACHE_DIR,
|
|
9
9
|
AGENT_PROJECT_METADATA_DIR,
|
|
@@ -246,7 +246,7 @@ function parseAgentRole(relativePath, fileContent, fullPath, idPrefix = "") {
|
|
|
246
246
|
let frontmatter;
|
|
247
247
|
try {
|
|
248
248
|
frontmatter = /** @type {{description?:string; import?:string}} */ (
|
|
249
|
-
|
|
249
|
+
parseYaml(match[1])
|
|
250
250
|
);
|
|
251
251
|
} catch (_err) {
|
|
252
252
|
return {
|
|
@@ -4,7 +4,7 @@ import { execFileSync } from "node:child_process";
|
|
|
4
4
|
import crypto from "node:crypto";
|
|
5
5
|
import fs from "node:fs/promises";
|
|
6
6
|
import path from "node:path";
|
|
7
|
-
import
|
|
7
|
+
import { parse as parseYaml } from "yaml";
|
|
8
8
|
import {
|
|
9
9
|
AGENT_CACHE_DIR,
|
|
10
10
|
AGENT_PROJECT_METADATA_DIR,
|
|
@@ -279,7 +279,7 @@ function parsePrompt(relativePath, fileContent, fullPath, idPrefix = "") {
|
|
|
279
279
|
try {
|
|
280
280
|
frontmatter =
|
|
281
281
|
/** @type {{description?:string; import?:string; "user-invocable"?:boolean}} */ (
|
|
282
|
-
|
|
282
|
+
parseYaml(match[1])
|
|
283
283
|
);
|
|
284
284
|
} catch (_err) {
|
|
285
285
|
return {
|
package/src/main.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { execFile } from "node:child_process";
|
|
|
5
5
|
* @returns {Promise<string>}
|
|
6
6
|
*/
|
|
7
7
|
export async function getGoogleCloudAccessToken(account) {
|
|
8
|
-
const accountOption = account?.endsWith("iam.gserviceaccount.com")
|
|
8
|
+
const accountOption = account?.endsWith(".iam.gserviceaccount.com")
|
|
9
9
|
? ["--impersonate-service-account", account]
|
|
10
10
|
: account
|
|
11
11
|
? [account]
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mock MCP server for testing.
|
|
3
|
-
* Speaks JSON-RPC 2.0 over stdio.
|
|
4
|
-
* Handles: initialize, notifications/initialized, tools/list, tools/call.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { createInterface } from "node:readline";
|
|
8
|
-
|
|
9
|
-
const rl = createInterface({ input: process.stdin });
|
|
10
|
-
|
|
11
|
-
rl.on("line", (line) => {
|
|
12
|
-
let msg;
|
|
13
|
-
try {
|
|
14
|
-
msg = JSON.parse(line);
|
|
15
|
-
} catch {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (msg.method === "initialize") {
|
|
20
|
-
respond(msg.id, {
|
|
21
|
-
protocolVersion: "2025-03-26",
|
|
22
|
-
capabilities: {},
|
|
23
|
-
serverInfo: { name: "mock", version: "0.0.0" },
|
|
24
|
-
});
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (msg.method === "notifications/initialized") {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (msg.method === "tools/list") {
|
|
33
|
-
respond(msg.id, {
|
|
34
|
-
tools: [
|
|
35
|
-
{
|
|
36
|
-
name: "echo",
|
|
37
|
-
description: "Echo tool",
|
|
38
|
-
inputSchema: {
|
|
39
|
-
type: "object",
|
|
40
|
-
properties: { text: { type: "string" } },
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
name: "add",
|
|
45
|
-
description: "Add numbers",
|
|
46
|
-
inputSchema: {
|
|
47
|
-
type: "object",
|
|
48
|
-
properties: {
|
|
49
|
-
a: { type: "number" },
|
|
50
|
-
b: { type: "number" },
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
],
|
|
55
|
-
});
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (msg.method === "tools/call") {
|
|
60
|
-
const { name, arguments: args } = msg.params;
|
|
61
|
-
if (name === "echo") {
|
|
62
|
-
respond(msg.id, { content: [{ type: "text", text: args.text }] });
|
|
63
|
-
} else if (name === "add") {
|
|
64
|
-
respond(msg.id, {
|
|
65
|
-
content: [{ type: "text", text: String(args.a + args.b) }],
|
|
66
|
-
});
|
|
67
|
-
} else if (name === "error_tool") {
|
|
68
|
-
respondError(msg.id, -1, "tool failed");
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
/** @param {number} id @param {unknown} result */
|
|
74
|
-
function respond(id, result) {
|
|
75
|
-
process.stdout.write(`${JSON.stringify({ jsonrpc: "2.0", id, result })}\n`);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** @param {number} id @param {number} code @param {string} message */
|
|
79
|
-
function respondError(id, code, message) {
|
|
80
|
-
process.stdout.write(
|
|
81
|
-
`${JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } })}\n`,
|
|
82
|
-
);
|
|
83
|
-
}
|