@meandmyagents/agent-runner 0.1.0 → 0.1.2
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 +14 -0
- package/package.json +1 -1
- package/src/runner.js +125 -7
package/README.md
CHANGED
|
@@ -13,6 +13,20 @@ process as `MAA_API_KEY`, so one Mac can run several agent profiles without
|
|
|
13
13
|
sharing identity. The launched agent uses MCP to start, complete, and drain the
|
|
14
14
|
remaining actionable cards.
|
|
15
15
|
|
|
16
|
+
Codex is launched with `--ask-for-approval never --sandbox danger-full-access`.
|
|
17
|
+
Claude is launched with `--permission-mode bypassPermissions`. The runner prompt
|
|
18
|
+
also includes the effective workflow instructions saved in MeAndMyAgents, tells
|
|
19
|
+
the agent not to wait for human answers, and tells it to verify, commit, and push
|
|
20
|
+
code changes before calling `complete_task`.
|
|
21
|
+
|
|
22
|
+
On macOS, `--launcher codex` will also look for the bundled Codex app executable
|
|
23
|
+
at `/Applications/Codex.app/Contents/Resources/codex` when `codex` is not on
|
|
24
|
+
`PATH`. If your launcher lives somewhere else, pass it explicitly:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
meandmyagents-runner watch --key maa_live_YOUR_AGENT_KEY --launcher codex --command /Applications/Codex.app/Contents/Resources/codex
|
|
28
|
+
```
|
|
29
|
+
|
|
16
30
|
```bash
|
|
17
31
|
meandmyagents-runner watch --key maa_live_YOUR_AGENT_KEY --launcher claude --once
|
|
18
32
|
```
|
package/package.json
CHANGED
package/src/runner.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { delimiter, join } from "node:path";
|
|
2
4
|
|
|
3
5
|
export const defaultApiUrl = "https://meandmyagents.com/api";
|
|
4
6
|
const supportedLaunchers = new Set(["codex", "claude"]);
|
|
5
7
|
|
|
6
8
|
export function parseRunnerArgs(argv = process.argv.slice(2)) {
|
|
7
9
|
const options = {
|
|
8
|
-
command: argv[0] ?? "help",
|
|
10
|
+
command: argv[0] === "--help" || argv[0] === "-h" ? "help" : argv[0] ?? "help",
|
|
9
11
|
apiUrl: defaultApiUrl,
|
|
10
12
|
intervalSeconds: 10,
|
|
11
13
|
key: "",
|
|
12
14
|
launcher: "codex",
|
|
15
|
+
launcherCommand: "",
|
|
13
16
|
once: false
|
|
14
17
|
};
|
|
15
18
|
|
|
@@ -34,6 +37,12 @@ export function parseRunnerArgs(argv = process.argv.slice(2)) {
|
|
|
34
37
|
continue;
|
|
35
38
|
}
|
|
36
39
|
|
|
40
|
+
if (arg === "--command" || arg === "-c") {
|
|
41
|
+
options.launcherCommand = argv[index + 1] ?? "";
|
|
42
|
+
index += 1;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
37
46
|
if (arg === "--interval") {
|
|
38
47
|
options.intervalSeconds = Number(argv[index + 1] ?? "10");
|
|
39
48
|
index += 1;
|
|
@@ -68,30 +77,58 @@ export function buildAgentPrompt({
|
|
|
68
77
|
agentName,
|
|
69
78
|
cardId,
|
|
70
79
|
eventId,
|
|
71
|
-
|
|
80
|
+
project,
|
|
81
|
+
projectName,
|
|
82
|
+
workflow
|
|
72
83
|
}) {
|
|
84
|
+
const workflowInstructions = Array.isArray(workflow?.instructions)
|
|
85
|
+
? workflow.instructions
|
|
86
|
+
: [];
|
|
87
|
+
const defaultBranch = project?.defaultBranch || "the default branch";
|
|
88
|
+
const codebaseLines = project?.repositoryUrl
|
|
89
|
+
? [
|
|
90
|
+
`Repository: ${project.repositoryUrl}`,
|
|
91
|
+
`Default branch: ${defaultBranch}`,
|
|
92
|
+
project.localPath ? `Local checkout path: ${project.localPath}` : null,
|
|
93
|
+
`If you modify code, run verification, then commit and push to ${defaultBranch} before complete_task.`
|
|
94
|
+
].filter(Boolean)
|
|
95
|
+
: ["This project has no repository URL, so treat it as non-code work unless list_my_tasks says otherwise."];
|
|
96
|
+
|
|
73
97
|
return [
|
|
74
98
|
`You are ${agentName}. MeAndMyAgents has assigned work in ${projectName}.`,
|
|
75
99
|
`Wake event: ${eventId}. First card that woke this session: ${cardId}.`,
|
|
100
|
+
"This is an autonomous runner wake-up. Do not wait for a human answer.",
|
|
101
|
+
"If you are blocked, add a card comment explaining the blocker and stop; do not sit idle asking a question.",
|
|
76
102
|
"Use the MeAndMyAgents MCP server now.",
|
|
77
103
|
"Call whoami to confirm your identity and project access.",
|
|
104
|
+
"Follow these workflow rules from MeAndMyAgents:",
|
|
105
|
+
...workflowInstructions.map((instruction) => `- ${instruction}`),
|
|
106
|
+
"Codebase context:",
|
|
107
|
+
...codebaseLines.map((line) => `- ${line}`),
|
|
78
108
|
"Call list_my_tasks, then start_task on the next actionable card before editing files.",
|
|
79
109
|
"Work only in the task codebase.localPath and only when codebase.canModifyCode is true.",
|
|
80
110
|
"Add comments with useful progress and completion summaries.",
|
|
81
|
-
"Call complete_task when a task is ready for human testing.",
|
|
111
|
+
"Call complete_task with a useful summary when a task is ready for human testing.",
|
|
82
112
|
"Call list_my_tasks again after each completion.",
|
|
83
113
|
"Keep taking the next task until no actionable tasks remain, then stop."
|
|
84
114
|
].join("\n");
|
|
85
115
|
}
|
|
86
116
|
|
|
87
|
-
export function buildLaunchCommand({
|
|
117
|
+
export function buildLaunchCommand({
|
|
118
|
+
launcher,
|
|
119
|
+
launcherCommand,
|
|
120
|
+
prompt,
|
|
121
|
+
cwd,
|
|
122
|
+
apiKey,
|
|
123
|
+
apiUrl
|
|
124
|
+
}) {
|
|
88
125
|
if (!supportedLaunchers.has(launcher)) {
|
|
89
126
|
throw new Error(`Unsupported launcher: ${launcher}`);
|
|
90
127
|
}
|
|
91
128
|
|
|
92
129
|
return {
|
|
93
|
-
command: launcher,
|
|
94
|
-
args:
|
|
130
|
+
command: launcherCommand || launcher,
|
|
131
|
+
args: buildLauncherArgs({ launcher, prompt, cwd }),
|
|
95
132
|
cwd,
|
|
96
133
|
env: {
|
|
97
134
|
MAA_API_KEY: apiKey,
|
|
@@ -100,6 +137,26 @@ export function buildLaunchCommand({ launcher, prompt, cwd, apiKey, apiUrl }) {
|
|
|
100
137
|
};
|
|
101
138
|
}
|
|
102
139
|
|
|
140
|
+
function buildLauncherArgs({ launcher, prompt, cwd }) {
|
|
141
|
+
if (launcher === "codex") {
|
|
142
|
+
return [
|
|
143
|
+
"--ask-for-approval",
|
|
144
|
+
"never",
|
|
145
|
+
"--sandbox",
|
|
146
|
+
"danger-full-access",
|
|
147
|
+
"--cd",
|
|
148
|
+
cwd,
|
|
149
|
+
prompt
|
|
150
|
+
];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (launcher === "claude") {
|
|
154
|
+
return ["--permission-mode", "bypassPermissions", prompt];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return [prompt];
|
|
158
|
+
}
|
|
159
|
+
|
|
103
160
|
export async function runCli(argv = process.argv.slice(2)) {
|
|
104
161
|
const options = parseRunnerArgs(argv);
|
|
105
162
|
|
|
@@ -171,10 +228,16 @@ async function launchEvent(options, event) {
|
|
|
171
228
|
agentName: event.agent?.name ?? options.launcher,
|
|
172
229
|
cardId: event.card?.id ?? "unknown-card",
|
|
173
230
|
eventId: event.id,
|
|
174
|
-
|
|
231
|
+
project: event.project,
|
|
232
|
+
projectName: event.project?.name ?? "this project",
|
|
233
|
+
workflow: event.workflow
|
|
175
234
|
});
|
|
176
235
|
const launch = buildLaunchCommand({
|
|
177
236
|
launcher: options.launcher,
|
|
237
|
+
launcherCommand: resolveLauncherCommand({
|
|
238
|
+
launcher: options.launcher,
|
|
239
|
+
launcherCommand: options.launcherCommand
|
|
240
|
+
}),
|
|
178
241
|
prompt,
|
|
179
242
|
cwd,
|
|
180
243
|
apiKey: options.key,
|
|
@@ -202,6 +265,60 @@ async function launchEvent(options, event) {
|
|
|
202
265
|
});
|
|
203
266
|
}
|
|
204
267
|
|
|
268
|
+
export function resolveLauncherCommand({
|
|
269
|
+
launcher,
|
|
270
|
+
launcherCommand = "",
|
|
271
|
+
pathEnv = process.env.PATH ?? "",
|
|
272
|
+
platform = process.platform,
|
|
273
|
+
homeDir = process.env.HOME || process.env.USERPROFILE || "",
|
|
274
|
+
exists = existsSync
|
|
275
|
+
}) {
|
|
276
|
+
if (launcherCommand) return launcherCommand;
|
|
277
|
+
if (!supportedLaunchers.has(launcher)) {
|
|
278
|
+
throw new Error(`Unsupported launcher: ${launcher}`);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (isCommandOnPath(launcher, { pathEnv, platform, exists })) return launcher;
|
|
282
|
+
|
|
283
|
+
const knownPath = knownLauncherPaths(launcher, platform, homeDir).find((path) =>
|
|
284
|
+
exists(path)
|
|
285
|
+
);
|
|
286
|
+
return knownPath ?? launcher;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function isCommandOnPath(command, { pathEnv, platform, exists }) {
|
|
290
|
+
const executableNames =
|
|
291
|
+
platform === "win32" ? [command, `${command}.cmd`, `${command}.exe`] : [command];
|
|
292
|
+
|
|
293
|
+
return pathEnv
|
|
294
|
+
.split(delimiter)
|
|
295
|
+
.filter(Boolean)
|
|
296
|
+
.some((pathDirectory) =>
|
|
297
|
+
executableNames.some((executableName) => exists(join(pathDirectory, executableName)))
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function knownLauncherPaths(launcher, platform, homeDir) {
|
|
302
|
+
if (platform === "darwin") {
|
|
303
|
+
const commonBinPaths = [
|
|
304
|
+
homeDir ? join(homeDir, ".local/bin", launcher) : "",
|
|
305
|
+
join("/opt/homebrew/bin", launcher),
|
|
306
|
+
join("/usr/local/bin", launcher)
|
|
307
|
+
].filter(Boolean);
|
|
308
|
+
|
|
309
|
+
if (launcher === "codex") {
|
|
310
|
+
return [
|
|
311
|
+
...commonBinPaths,
|
|
312
|
+
"/Applications/Codex.app/Contents/Resources/codex"
|
|
313
|
+
];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return commonBinPaths;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return homeDir ? [join(homeDir, ".local/bin", launcher)] : [];
|
|
320
|
+
}
|
|
321
|
+
|
|
205
322
|
function normalizeApiUrl(value) {
|
|
206
323
|
return (value || defaultApiUrl).replace(/\/$/, "").replace(/\/mcp$/, "");
|
|
207
324
|
}
|
|
@@ -232,6 +349,7 @@ Options:
|
|
|
232
349
|
--key, -k Required agent-bound API key.
|
|
233
350
|
--api-url, -u API base URL. Defaults to ${defaultApiUrl}.
|
|
234
351
|
--launcher, -l Visible CLI launcher: codex or claude.
|
|
352
|
+
--command, -c Optional explicit executable path, e.g. /Applications/Codex.app/Contents/Resources/codex.
|
|
235
353
|
--interval Poll interval in seconds. Defaults to 10.
|
|
236
354
|
--once Check once, launch at most one visible session, then exit.
|
|
237
355
|
`;
|