@iinm/plain-agent 1.8.3 → 1.8.4

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.
Files changed (86) hide show
  1. package/README.md +2 -2
  2. package/bin/plain +1 -1
  3. package/config/config.predefined.json +1 -1
  4. package/config/prompts.predefined/shortcuts/configure.md +1 -1
  5. package/dist/main.mjs +473 -0
  6. package/dist/main.mjs.map +7 -0
  7. package/package.json +5 -7
  8. package/src/agent.d.ts +0 -52
  9. package/src/agent.mjs +0 -204
  10. package/src/agentLoop.mjs +0 -419
  11. package/src/agentState.mjs +0 -41
  12. package/src/claudeCodePlugin.mjs +0 -164
  13. package/src/cliArgs.mjs +0 -175
  14. package/src/cliBatch.mjs +0 -147
  15. package/src/cliCommands.mjs +0 -283
  16. package/src/cliCompleter.mjs +0 -227
  17. package/src/cliCost.mjs +0 -309
  18. package/src/cliFormatter.mjs +0 -413
  19. package/src/cliInteractive.mjs +0 -529
  20. package/src/cliInterruptTransform.mjs +0 -51
  21. package/src/cliMuteTransform.mjs +0 -26
  22. package/src/cliPasteTransform.mjs +0 -183
  23. package/src/config.d.ts +0 -36
  24. package/src/config.mjs +0 -197
  25. package/src/context/loadAgentRoles.mjs +0 -283
  26. package/src/context/loadPrompts.mjs +0 -324
  27. package/src/context/loadUserMessageContext.mjs +0 -147
  28. package/src/costTracker.mjs +0 -210
  29. package/src/env.mjs +0 -44
  30. package/src/main.mjs +0 -279
  31. package/src/mcpClient.mjs +0 -351
  32. package/src/mcpIntegration.mjs +0 -160
  33. package/src/model.d.ts +0 -109
  34. package/src/modelCaller.mjs +0 -32
  35. package/src/modelDefinition.d.ts +0 -92
  36. package/src/prompt.mjs +0 -138
  37. package/src/providers/anthropic.d.ts +0 -248
  38. package/src/providers/anthropic.mjs +0 -587
  39. package/src/providers/bedrock.d.ts +0 -249
  40. package/src/providers/bedrock.mjs +0 -700
  41. package/src/providers/gemini.d.ts +0 -208
  42. package/src/providers/gemini.mjs +0 -754
  43. package/src/providers/openai.d.ts +0 -281
  44. package/src/providers/openai.mjs +0 -544
  45. package/src/providers/openaiCompatible.d.ts +0 -147
  46. package/src/providers/openaiCompatible.mjs +0 -652
  47. package/src/providers/platform/awsSigV4.mjs +0 -184
  48. package/src/providers/platform/azure.mjs +0 -42
  49. package/src/providers/platform/bedrock.mjs +0 -78
  50. package/src/providers/platform/googleCloud.mjs +0 -34
  51. package/src/subagent.mjs +0 -265
  52. package/src/tmpfile.mjs +0 -27
  53. package/src/tool.d.ts +0 -74
  54. package/src/toolExecutor.mjs +0 -236
  55. package/src/toolInputValidator.mjs +0 -183
  56. package/src/toolUseApprover.mjs +0 -99
  57. package/src/tools/askURL.mjs +0 -209
  58. package/src/tools/askWeb.mjs +0 -208
  59. package/src/tools/compactContext.d.ts +0 -4
  60. package/src/tools/compactContext.mjs +0 -87
  61. package/src/tools/delegateToSubagent.d.ts +0 -4
  62. package/src/tools/delegateToSubagent.mjs +0 -48
  63. package/src/tools/execCommand.d.ts +0 -22
  64. package/src/tools/execCommand.mjs +0 -200
  65. package/src/tools/patchFile.d.ts +0 -4
  66. package/src/tools/patchFile.mjs +0 -133
  67. package/src/tools/reportAsSubagent.d.ts +0 -3
  68. package/src/tools/reportAsSubagent.mjs +0 -44
  69. package/src/tools/tmuxCommand.d.ts +0 -14
  70. package/src/tools/tmuxCommand.mjs +0 -194
  71. package/src/tools/writeFile.d.ts +0 -4
  72. package/src/tools/writeFile.mjs +0 -56
  73. package/src/usageStore.mjs +0 -167
  74. package/src/utils/evalJSONConfig.mjs +0 -72
  75. package/src/utils/matchValue.d.ts +0 -6
  76. package/src/utils/matchValue.mjs +0 -40
  77. package/src/utils/noThrow.mjs +0 -31
  78. package/src/utils/notify.mjs +0 -29
  79. package/src/utils/parseFileRange.mjs +0 -18
  80. package/src/utils/readFileRange.mjs +0 -33
  81. package/src/utils/retryOnError.mjs +0 -41
  82. package/src/voiceInput.mjs +0 -61
  83. package/src/voiceInputGemini.mjs +0 -105
  84. package/src/voiceInputOpenAI.mjs +0 -104
  85. package/src/voiceInputSession.mjs +0 -543
  86. package/src/voiceToggleKey.mjs +0 -62
@@ -1,41 +0,0 @@
1
- /**
2
- * @import { Message } from "./model"
3
- */
4
-
5
- /**
6
- * @typedef {ReturnType<typeof createStateManager>} StateManager
7
- */
8
-
9
- /**
10
- * @typedef {Object} StateEventHandlers
11
- * @property {(messages: Message[]) => void} onMessagesAppended
12
- */
13
-
14
- /**
15
- * Creates a state manager for message handling.
16
- * @param {Message[]} initialMessages
17
- * @param {StateEventHandlers} handlers
18
- */
19
- export function createStateManager(initialMessages, handlers) {
20
- /** @type {Message[]} */
21
- let messages = [...initialMessages];
22
-
23
- return {
24
- /** Get all messages (immutable copy) */
25
- getMessages: () => [...messages],
26
-
27
- /** Get message at specific index (supports -1 for last) */
28
- getMessageAt: /** @param {number} index */ (index) => messages.at(index),
29
-
30
- /** Append messages */
31
- appendMessages: /** @param {Message[]} newMessages */ (newMessages) => {
32
- messages = [...messages, ...newMessages];
33
- handlers.onMessagesAppended(newMessages);
34
- },
35
-
36
- /** Replace all messages */
37
- setMessages: /** @param {Message[]} newMessages */ (newMessages) => {
38
- messages = [...newMessages];
39
- },
40
- };
41
- }
@@ -1,164 +0,0 @@
1
- import { execFile } from "node:child_process";
2
- import fs from "node:fs/promises";
3
- import path from "node:path";
4
- import { loadAppConfig } from "./config.mjs";
5
- import { CLAUDE_CODE_PLUGIN_DIR } from "./env.mjs";
6
-
7
- /**
8
- * @typedef {Object} ClaudeCodePluginRepo
9
- * @property {string} source
10
- * @property {Array<{name: string, path: string, only?: string}>} plugins
11
- */
12
-
13
- /**
14
- * @typedef {Object} ClaudeCodePlugin
15
- * @property {string} name
16
- * @property {string} path
17
- * @property {RegExp} [only]
18
- */
19
-
20
- /**
21
- * Resolve plugin paths from hierarchical config structure.
22
- * Converts {source, plugins} to flat {name, path, only} with full paths.
23
- * @param {ClaudeCodePluginRepo[]} repos
24
- * @returns {ClaudeCodePlugin[]}
25
- */
26
- export function resolvePluginPaths(repos) {
27
- if (!repos) return [];
28
-
29
- /** @type {ClaudeCodePlugin[]} */
30
- const result = [];
31
-
32
- for (const repo of repos) {
33
- const ownerRepo = extractOwnerRepo(repo.source);
34
- if (!ownerRepo) {
35
- console.warn(`Invalid source URL: ${repo.source}`);
36
- continue;
37
- }
38
-
39
- for (const plugin of repo.plugins) {
40
- // Compile only pattern to RegExp
41
- let only;
42
- if (plugin.only) {
43
- try {
44
- only = new RegExp(plugin.only);
45
- } catch (err) {
46
- console.warn(
47
- `Invalid regex pattern "${plugin.only}" for plugin "${plugin.name}":`,
48
- err instanceof Error ? err.message : String(err),
49
- );
50
- }
51
- }
52
-
53
- result.push({
54
- name: plugin.name,
55
- path: path.join(CLAUDE_CODE_PLUGIN_DIR, ownerRepo, plugin.path),
56
- only,
57
- });
58
- }
59
- }
60
-
61
- return result;
62
- }
63
-
64
- /**
65
- * Install Claude Code plugins by cloning repositories.
66
- */
67
- export async function installClaudeCodePlugins() {
68
- const { appConfig } = await loadAppConfig({ skipTrustCheck: true });
69
- const repos = appConfig.claudeCodePlugins ?? [];
70
-
71
- if (repos.length === 0) {
72
- console.log("No plugins configured.");
73
- return;
74
- }
75
-
76
- let installed = 0;
77
- let skipped = 0;
78
- let failed = 0;
79
-
80
- // Track paths for summary
81
- /** @type {string[]} */
82
- const installedPaths = [];
83
- /** @type {string[]} */
84
- const skippedPaths = [];
85
-
86
- // Ensure plugin directory exists
87
- await fs.mkdir(CLAUDE_CODE_PLUGIN_DIR, { recursive: true });
88
-
89
- for (const repo of repos) {
90
- const ownerRepo = extractOwnerRepo(repo.source);
91
- if (!ownerRepo) {
92
- console.error(`❌ Invalid source URL: ${repo.source}`);
93
- failed++;
94
- continue;
95
- }
96
-
97
- const destPath = path.join(CLAUDE_CODE_PLUGIN_DIR, ownerRepo);
98
-
99
- // Check if already exists
100
- const exists = await fs
101
- .access(destPath)
102
- .then(() => true)
103
- .catch(() => false);
104
- if (exists) {
105
- console.log(`⏭️ Skipping ${repo.source} → ${destPath}: already installed`);
106
- skippedPaths.push(destPath);
107
- skipped++;
108
- continue;
109
- }
110
-
111
- // Clone the repository
112
- console.log(`📥 Installing ${repo.source}...`);
113
- try {
114
- await new Promise((resolve, reject) => {
115
- execFile(
116
- "git",
117
- ["clone", "--depth", "1", repo.source, destPath],
118
- (err) => {
119
- if (err) reject(err);
120
- else resolve(undefined);
121
- },
122
- );
123
- });
124
- console.log(`✅ Installed to ${destPath}`);
125
- installedPaths.push(destPath);
126
- installed++;
127
- } catch (error) {
128
- console.error(
129
- `❌ Failed to install: ${error instanceof Error ? error.message : String(error)}`,
130
- );
131
- failed++;
132
- }
133
- }
134
-
135
- console.log(
136
- `\n📊 Summary: ${installed} installed, ${skipped} skipped, ${failed} failed`,
137
- );
138
-
139
- if (installedPaths.length > 0) {
140
- console.log("\nInstalled:");
141
- for (const p of installedPaths) {
142
- console.log(` • ${p}`);
143
- }
144
- }
145
-
146
- if (skippedPaths.length > 0) {
147
- console.log("\nSkipped:");
148
- for (const p of skippedPaths) {
149
- console.log(` • ${p}`);
150
- }
151
- }
152
- }
153
-
154
- /**
155
- * Extract owner/repo from source URL.
156
- * @param {string} source
157
- * @returns {string|null}
158
- */
159
- function extractOwnerRepo(source) {
160
- // Handle: https://github.com/owner/repo
161
- // Handle: git@github.com:owner/repo.git
162
- const match = source.match(/[:/]([^/]+\/[^/]+?)(?:\.git)?$/);
163
- return match ? match[1] : null;
164
- }
package/src/cliArgs.mjs DELETED
@@ -1,175 +0,0 @@
1
- /**
2
- * @typedef {HelpSubcommand | InteractiveSubcommand | BatchSubcommand | ListModelsSubcommand | InstallClaudeCodePluginsSubcommand | CostSubcommand} Subcommand
3
- */
4
-
5
- /**
6
- * @typedef {{ type: 'help' }} HelpSubcommand
7
- */
8
-
9
- /**
10
- * @typedef {{ type: 'interactive', config: string[], model: string | null }} InteractiveSubcommand
11
- */
12
-
13
- /**
14
- * @typedef {{ type: 'batch', task: string, config: string[], model: string | null }} BatchSubcommand
15
- */
16
-
17
- /**
18
- * @typedef {{ type: 'list-models' }} ListModelsSubcommand
19
- */
20
-
21
- /**
22
- * @typedef {{ type: 'install-claude-code-plugins' }} InstallClaudeCodePluginsSubcommand
23
- */
24
-
25
- /**
26
- * @typedef {{ type: 'cost', from: string | null, to: string | null }} CostSubcommand
27
- */
28
-
29
- /**
30
- * @typedef {Object} CliArgs
31
- * @property {Subcommand} subcommand - The subcommand to execute
32
- */
33
-
34
- /**
35
- * Parse command-line arguments.
36
- * @param {string[]} argv - process.argv or similar
37
- * @returns {CliArgs}
38
- */
39
- export function parseCliArgs(argv) {
40
- const args = argv.slice(2);
41
- const subcommandName = args[0];
42
-
43
- if (["-h", "--help", "help"].includes(subcommandName)) {
44
- return {
45
- subcommand: { type: "help" },
46
- };
47
- }
48
-
49
- if (!subcommandName || subcommandName.startsWith("-")) {
50
- // Interactive mode (default)
51
- const config = [];
52
- let model = null;
53
-
54
- for (let i = 0; i < args.length; i++) {
55
- if (args[i] === "-m" || args[i] === "--model") {
56
- if (args[i + 1]) {
57
- model = args[i + 1];
58
- i++;
59
- }
60
- } else if (args[i] === "-c" || args[i] === "--config") {
61
- if (args[i + 1]) {
62
- config.push(args[i + 1]);
63
- i++;
64
- }
65
- }
66
- }
67
-
68
- return {
69
- subcommand: { type: "interactive", config, model },
70
- };
71
- }
72
-
73
- if (subcommandName === "batch") {
74
- const batchArgs = args.slice(1);
75
-
76
- let task = null;
77
- let model = null;
78
- const config = [];
79
-
80
- for (let i = 0; i < batchArgs.length; i++) {
81
- if (batchArgs[i] === "-m" || batchArgs[i] === "--model") {
82
- if (batchArgs[i + 1]) {
83
- model = batchArgs[i + 1];
84
- i++;
85
- }
86
- } else if (batchArgs[i] === "-c" || batchArgs[i] === "--config") {
87
- if (batchArgs[i + 1]) {
88
- config.push(batchArgs[i + 1]);
89
- i++;
90
- }
91
- } else if (!batchArgs[i].startsWith("-") && !task) {
92
- task = batchArgs[i];
93
- }
94
- }
95
-
96
- return {
97
- subcommand: { type: "batch", task: task || "", config, model },
98
- };
99
- }
100
-
101
- if (subcommandName === "list-models") {
102
- return {
103
- subcommand: { type: "list-models" },
104
- };
105
- }
106
-
107
- if (subcommandName === "install-claude-code-plugins") {
108
- return {
109
- subcommand: { type: "install-claude-code-plugins" },
110
- };
111
- }
112
-
113
- if (subcommandName === "cost") {
114
- const costArgs = args.slice(1);
115
- let from = null;
116
- let to = null;
117
- for (let i = 0; i < costArgs.length; i++) {
118
- if (costArgs[i] === "--from") {
119
- if (costArgs[i + 1]) {
120
- from = costArgs[i + 1];
121
- i++;
122
- }
123
- } else if (costArgs[i] === "--to") {
124
- if (costArgs[i + 1]) {
125
- to = costArgs[i + 1];
126
- i++;
127
- }
128
- }
129
- }
130
- return {
131
- subcommand: { type: "cost", from, to },
132
- };
133
- }
134
-
135
- return {
136
- subcommand: { type: "help" },
137
- };
138
- }
139
-
140
- /**
141
- * Print help message and exit.
142
- * @param {number} [exitCode] - Exit code (default: 0)
143
- */
144
- export function printHelp(exitCode = 0) {
145
- console.log(`
146
- Usage: plain [options]
147
- plain batch [options] <task>
148
- plain cost [--from YYYY-MM-DD] [--to YYYY-MM-DD]
149
- plain list-models
150
- plain install-claude-code-plugins
151
-
152
- Options:
153
- -m, --model <model+variant> Model to use
154
- -h, --help Show this help message
155
- -c, --config <file> Config file to load (repeatable)
156
-
157
- Subcommands:
158
- batch <task> Run in batch mode with the given task instruction.
159
- Config files are NOT auto-loaded in batch mode;
160
- use -c to specify config files explicitly.
161
- cost Show aggregated token cost per day for a period.
162
- Defaults to the first day of the current month
163
- through today.
164
- list-models List available models
165
- install-claude-code-plugins Install Claude Code plugins
166
-
167
- Examples:
168
- plain -m gpt-5.4+thinking-medium
169
- plain batch \\
170
- -c ~/.config/plain-agent/config.local.json \\
171
- -c .plain-agent/config.json \\
172
- "Add tests for ..."
173
- `);
174
- process.exit(exitCode);
175
- }
package/src/cliBatch.mjs DELETED
@@ -1,147 +0,0 @@
1
- /**
2
- * @import { UserEventEmitter, AgentEventEmitter, AgentCommands } from "./agent"
3
- */
4
-
5
- import { formatCostForBatch } from "./cliFormatter.mjs";
6
- import { appendUsageRecord, buildUsageRecord } from "./usageStore.mjs";
7
-
8
- /**
9
- * @typedef {object} BatchSessionOptions
10
- * @property {UserEventEmitter} userEventEmitter
11
- * @property {AgentEventEmitter} agentEventEmitter
12
- * @property {AgentCommands} agentCommands
13
- * @property {string} task - Task instruction to execute
14
- * @property {string} sessionId
15
- * @property {string} modelName
16
- * @property {boolean} sandbox
17
- * @property {Date} startTime
18
- * @property {() => Promise<void>} onStop
19
- */
20
-
21
- /**
22
- * Start a batch session and execute the task.
23
- * Events are output as JSON Lines (1 line = 1 JSON object).
24
- *
25
- * @param {BatchSessionOptions} options
26
- * @returns {Promise<void>}
27
- */
28
- export async function startBatchSession({
29
- userEventEmitter,
30
- agentEventEmitter,
31
- agentCommands,
32
- task,
33
- sessionId,
34
- modelName,
35
- sandbox,
36
- startTime,
37
- onStop,
38
- }) {
39
- setupEventHandlers(agentEventEmitter, { sessionId, modelName, sandbox });
40
-
41
- userEventEmitter.emit("userInput", [{ type: "text", text: task }]);
42
-
43
- await new Promise((/** @type {(value?: void) => void} */ resolve) => {
44
- agentEventEmitter.on("turnEnd", async () => {
45
- const costSummary = agentCommands.getCostSummary();
46
-
47
- outputEvent({
48
- type: "session_end",
49
- timestamp: new Date().toISOString(),
50
- cost: formatCostForBatch(costSummary),
51
- });
52
-
53
- try {
54
- const record = buildUsageRecord({
55
- sessionId,
56
- mode: "batch",
57
- modelName,
58
- workingDir: process.cwd(),
59
- costSummary,
60
- now: startTime,
61
- });
62
- if (record) {
63
- await appendUsageRecord(record);
64
- }
65
- } catch (err) {
66
- const message = err instanceof Error ? err.message : String(err);
67
- outputEvent({
68
- type: "error",
69
- error: { message: `failed to record usage: ${message}` },
70
- timestamp: new Date().toISOString(),
71
- });
72
- }
73
-
74
- await onStop();
75
- resolve();
76
- });
77
- });
78
-
79
- process.exit(0);
80
- }
81
-
82
- /**
83
- * Setup event handlers for batch mode.
84
- * Output events as JSON Lines.
85
- *
86
- * @param {AgentEventEmitter} agentEventEmitter
87
- * @param {{ sessionId: string, modelName: string, sandbox: boolean }} meta
88
- */
89
- function setupEventHandlers(
90
- agentEventEmitter,
91
- { sessionId, modelName, sandbox },
92
- ) {
93
- outputEvent({
94
- type: "session_start",
95
- sessionId,
96
- modelName,
97
- sandbox,
98
- timestamp: new Date().toISOString(),
99
- });
100
-
101
- agentEventEmitter.on("message", (message) => {
102
- outputEvent({
103
- type: "message",
104
- message,
105
- timestamp: new Date().toISOString(),
106
- });
107
- });
108
-
109
- agentEventEmitter.on("error", (error) => {
110
- outputEvent({
111
- type: "error",
112
- error: {
113
- message: error.message,
114
- stack: error.stack,
115
- },
116
- timestamp: new Date().toISOString(),
117
- });
118
-
119
- process.exit(1);
120
- });
121
-
122
- agentEventEmitter.on("subagentSwitched", (subagent) => {
123
- outputEvent({
124
- type: "subagent_switched",
125
- subagent,
126
- timestamp: new Date().toISOString(),
127
- });
128
- });
129
-
130
- agentEventEmitter.on("providerTokenUsage", (usage) => {
131
- outputEvent({
132
- type: "token_usage",
133
- usage,
134
- timestamp: new Date().toISOString(),
135
- });
136
- });
137
- }
138
-
139
- /**
140
- * Output an event as JSON Lines format.
141
- * Each event is a single line of JSON.
142
- *
143
- * @param {object} event
144
- */
145
- function outputEvent(event) {
146
- console.log(JSON.stringify(event));
147
- }