@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 CHANGED
@@ -1,3 +1,7 @@
1
+ <p align="center">
2
+ <img src="https://pub-0bb49aa929f242d49c89ed8c297932b5.r2.dev/plain-agent/plain-agent-logo.png" alt="plain-agent logo" width="320">
3
+ </p>
4
+
1
5
  # Plain Agent
2
6
 
3
7
  A lightweight CLI-based coding agent.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iinm/plain-agent",
3
- "version": "1.8.1",
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": "./bin/plain",
13
- "plain-notify-desktop": "./bin/plain-notify-desktop",
14
- "plain-sandbox": "./sandbox/bin/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/utils/test/"
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
- "js-yaml": "^4.1.1"
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);
@@ -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 yaml from "js-yaml";
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
- yaml.load(match[1])
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 yaml from "js-yaml";
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
- yaml.load(match[1])
282
+ parseYaml(match[1])
283
283
  );
284
284
  } catch (_err) {
285
285
  return {
package/src/main.mjs CHANGED
@@ -248,6 +248,7 @@ if (cliArgs.subcommand.type === "cost") {
248
248
  sessionId,
249
249
  modelName: modelNameWithVariant,
250
250
  sandbox: Boolean(appConfig.sandbox),
251
+ startTime,
251
252
  onStop: async () => {
252
253
  for (const cleanup of mcpCleanups) {
253
254
  await cleanup();
@@ -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
- }