mcoda 0.1.7 → 0.1.9
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/CHANGELOG.md +4 -1
- package/README.md +35 -0
- package/dist/bin/McodaEntrypoint.d.ts.map +1 -1
- package/dist/bin/McodaEntrypoint.js +11 -1
- package/dist/commands/agents/AgentRunCommand.d.ts +4 -0
- package/dist/commands/agents/AgentRunCommand.d.ts.map +1 -0
- package/dist/commands/agents/AgentRunCommand.js +126 -0
- package/dist/commands/agents/AgentsCommands.d.ts.map +1 -1
- package/dist/commands/agents/AgentsCommands.js +51 -1
- package/dist/commands/agents/GatewayAgentCommand.d.ts.map +1 -1
- package/dist/commands/agents/GatewayAgentCommand.js +23 -85
- package/dist/commands/backlog/OrderTasksCommand.d.ts +1 -0
- package/dist/commands/backlog/OrderTasksCommand.d.ts.map +1 -1
- package/dist/commands/backlog/OrderTasksCommand.js +18 -0
- package/dist/commands/docs/DocsCommands.d.ts +4 -0
- package/dist/commands/docs/DocsCommands.d.ts.map +1 -1
- package/dist/commands/docs/DocsCommands.js +52 -2
- package/dist/commands/openapi/OpenapiCommands.d.ts +1 -0
- package/dist/commands/openapi/OpenapiCommands.d.ts.map +1 -1
- package/dist/commands/openapi/OpenapiCommands.js +20 -1
- package/dist/commands/planning/CreateTasksCommand.d.ts +15 -0
- package/dist/commands/planning/CreateTasksCommand.d.ts.map +1 -1
- package/dist/commands/planning/CreateTasksCommand.js +135 -2
- package/dist/commands/planning/QaTasksCommand.d.ts +2 -0
- package/dist/commands/planning/QaTasksCommand.d.ts.map +1 -1
- package/dist/commands/planning/QaTasksCommand.js +30 -1
- package/dist/commands/planning/RefineTasksCommand.d.ts +1 -0
- package/dist/commands/planning/RefineTasksCommand.d.ts.map +1 -1
- package/dist/commands/planning/RefineTasksCommand.js +20 -1
- package/dist/commands/review/CodeReviewCommand.d.ts +1 -0
- package/dist/commands/review/CodeReviewCommand.d.ts.map +1 -1
- package/dist/commands/review/CodeReviewCommand.js +20 -0
- package/dist/commands/work/GatewayTrioCommand.d.ts +42 -0
- package/dist/commands/work/GatewayTrioCommand.d.ts.map +1 -0
- package/dist/commands/work/GatewayTrioCommand.js +935 -0
- package/dist/commands/work/WorkOnTasksCommand.d.ts +3 -0
- package/dist/commands/work/WorkOnTasksCommand.d.ts.map +1 -1
- package/dist/commands/work/WorkOnTasksCommand.js +72 -0
- package/dist/commands/workspace/SetWorkspaceCommand.d.ts.map +1 -1
- package/dist/commands/workspace/SetWorkspaceCommand.js +38 -13
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -13,6 +13,41 @@ mcoda set-workspace --workspace-root .
|
|
|
13
13
|
mcoda docs pdr generate --workspace-root . --project WEB --rfp-path docs/rfp/web.md --agent codex
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
## Docdex & QA
|
|
17
|
+
- mcoda depends on the `docdex` CLI for doc search and context stitching.
|
|
18
|
+
- Run `docdex setup` to install Playwright and at least one browser for `qa-tasks`.
|
|
19
|
+
- Docdex stores state under `~/.docdex`; mcoda does not create repo-local `.docdex` folders.
|
|
20
|
+
- If `~/.docdex/agents.md` exists, it is prepended to every agent run.
|
|
21
|
+
|
|
22
|
+
## Workspace layout
|
|
23
|
+
- `.mcoda/config.json` for defaults (docdex URL, branch metadata, telemetry preferences).
|
|
24
|
+
- `.mcoda/mcoda.db` for backlog, jobs, and telemetry.
|
|
25
|
+
- `.mcoda/docs/` for generated artifacts.
|
|
26
|
+
|
|
27
|
+
## Common commands
|
|
28
|
+
- Docs: `mcoda docs pdr generate`, `mcoda docs sds generate`
|
|
29
|
+
- Specs: `mcoda openapi-from-docs`
|
|
30
|
+
- Planning: `mcoda create-tasks`, `mcoda refine-tasks`, `mcoda order-tasks`
|
|
31
|
+
- Execution: `mcoda work-on-tasks`, `mcoda code-review`, `mcoda qa-tasks`
|
|
32
|
+
- Backlog: `mcoda backlog`, `mcoda task`
|
|
33
|
+
- Jobs/telemetry: `mcoda jobs`, `mcoda tokens`, `mcoda telemetry`
|
|
34
|
+
- Agents: `mcoda test-agent`, `mcoda agent-run`
|
|
35
|
+
- Updates: `mcoda update --check`
|
|
36
|
+
|
|
37
|
+
## Configuration
|
|
38
|
+
Environment variables are optional overrides for workspace settings:
|
|
39
|
+
- `MCODA_DOCDEX_URL` to point at a docdex server.
|
|
40
|
+
- `MCODA_API_BASE_URL` or `MCODA_JOBS_API_URL` for job APIs.
|
|
41
|
+
- `MCODA_TELEMETRY` set to `off` to disable telemetry.
|
|
42
|
+
- `MCODA_STREAM_IO=1` to emit agent I/O lines to stderr.
|
|
43
|
+
|
|
44
|
+
## Programmatic usage
|
|
45
|
+
```ts
|
|
46
|
+
import { McodaEntrypoint } from "mcoda";
|
|
47
|
+
|
|
48
|
+
await McodaEntrypoint.run(["--version"]);
|
|
49
|
+
```
|
|
50
|
+
|
|
16
51
|
## Documentation
|
|
17
52
|
Full docs live in the repository:
|
|
18
53
|
- README: https://github.com/bekirdag/mcoda
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McodaEntrypoint.d.ts","sourceRoot":"","sources":["../../src/bin/McodaEntrypoint.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"McodaEntrypoint.d.ts","sourceRoot":"","sources":["../../src/bin/McodaEntrypoint.ts"],"names":[],"mappings":";AA2BA,qBAAa,eAAe;WACb,GAAG,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;CA4IxE"}
|
|
@@ -15,12 +15,14 @@ import { OrderTasksCommand } from "../commands/backlog/OrderTasksCommand.js";
|
|
|
15
15
|
import { EstimateCommands } from "../commands/estimate/EstimateCommands.js";
|
|
16
16
|
import { TelemetryCommands } from "../commands/telemetry/TelemetryCommands.js";
|
|
17
17
|
import { WorkOnTasksCommand } from "../commands/work/WorkOnTasksCommand.js";
|
|
18
|
+
import { GatewayTrioCommand } from "../commands/work/GatewayTrioCommand.js";
|
|
18
19
|
import { CodeReviewCommand } from "../commands/review/CodeReviewCommand.js";
|
|
19
20
|
import { QaTasksCommand } from "../commands/planning/QaTasksCommand.js";
|
|
20
21
|
import { MigrateTasksCommand } from "../commands/planning/MigrateTasksCommand.js";
|
|
21
22
|
import { UpdateCommands } from "../commands/update/UpdateCommands.js";
|
|
22
23
|
import { RoutingCommands } from "../commands/routing/RoutingCommands.js";
|
|
23
24
|
import { TestAgentCommand } from "../commands/agents/TestAgentCommand.js";
|
|
25
|
+
import { AgentRunCommand } from "../commands/agents/AgentRunCommand.js";
|
|
24
26
|
import { SetWorkspaceCommand } from "../commands/workspace/SetWorkspaceCommand.js";
|
|
25
27
|
export class McodaEntrypoint {
|
|
26
28
|
static async run(argv = process.argv.slice(2)) {
|
|
@@ -40,7 +42,7 @@ export class McodaEntrypoint {
|
|
|
40
42
|
return;
|
|
41
43
|
}
|
|
42
44
|
if (!command) {
|
|
43
|
-
throw new Error("Usage: mcoda <agent|gateway-agent|routing|docs|openapi|job|jobs|tokens|telemetry|create-tasks|migrate-tasks|refine-tasks|order-tasks|tasks|work-on-tasks|code-review|qa-tasks|backlog|task|task-detail|estimate|update|set-workspace|pdr|sds> [...args]\n" +
|
|
45
|
+
throw new Error("Usage: mcoda <agent|gateway-agent|test-agent|agent-run|routing|docs|openapi|job|jobs|tokens|telemetry|create-tasks|migrate-tasks|refine-tasks|order-tasks|tasks|work-on-tasks|gateway-trio|code-review|qa-tasks|backlog|task|task-detail|estimate|update|set-workspace|pdr|sds> [...args]\n" +
|
|
44
46
|
"Routing: use `mcoda routing defaults` to view/update workspace/global defaults, `mcoda routing preview|explain` to inspect agent selection/provenance (override → workspace_default → global_default).\n" +
|
|
45
47
|
"Aliases: `tasks order-by-deps` forwards to `order-tasks` (dependency-aware ordering), `task`/`task-detail` show a single task.\n" +
|
|
46
48
|
"Job commands (mcoda job --help for details): list|status|watch|logs|inspect|resume|cancel|tokens\n" +
|
|
@@ -58,6 +60,10 @@ export class McodaEntrypoint {
|
|
|
58
60
|
await TestAgentCommand.run(rest);
|
|
59
61
|
return;
|
|
60
62
|
}
|
|
63
|
+
if (command === "agent-run") {
|
|
64
|
+
await AgentRunCommand.run(rest);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
61
67
|
if (command === "routing") {
|
|
62
68
|
await RoutingCommands.run(rest);
|
|
63
69
|
return;
|
|
@@ -126,6 +132,10 @@ export class McodaEntrypoint {
|
|
|
126
132
|
await WorkOnTasksCommand.run(rest);
|
|
127
133
|
return;
|
|
128
134
|
}
|
|
135
|
+
if (command === "gateway-trio") {
|
|
136
|
+
await GatewayTrioCommand.run(rest);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
129
139
|
if (command === "code-review") {
|
|
130
140
|
await CodeReviewCommand.run(rest);
|
|
131
141
|
return;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentRunCommand.d.ts","sourceRoot":"","sources":["../../../src/commands/agents/AgentRunCommand.ts"],"names":[],"mappings":"AAyDA,qBAAa,eAAe;WACb,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA0EhD"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { AgentsApi } from "@mcoda/core";
|
|
3
|
+
const USAGE = "Usage: mcoda agent-run <NAME> [--prompt \"<text>\"] [--prompt-file <PATH>] [--task-file <PATH>] [--json]";
|
|
4
|
+
const parseArgs = (argv) => {
|
|
5
|
+
const flags = {};
|
|
6
|
+
const positionals = [];
|
|
7
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
8
|
+
const arg = argv[i];
|
|
9
|
+
if (arg.startsWith("--")) {
|
|
10
|
+
const key = arg.replace(/^--/, "");
|
|
11
|
+
const next = argv[i + 1];
|
|
12
|
+
if (next && !next.startsWith("--")) {
|
|
13
|
+
const existing = flags[key];
|
|
14
|
+
if (Array.isArray(existing)) {
|
|
15
|
+
flags[key] = [...existing, next];
|
|
16
|
+
}
|
|
17
|
+
else if (typeof existing === "string") {
|
|
18
|
+
flags[key] = [existing, next];
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
flags[key] = next;
|
|
22
|
+
}
|
|
23
|
+
i += 1;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
flags[key] = true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
positionals.push(arg);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { flags, positionals };
|
|
34
|
+
};
|
|
35
|
+
const readTaskFile = async (filePath) => {
|
|
36
|
+
const raw = await fs.readFile(filePath, "utf8");
|
|
37
|
+
return raw
|
|
38
|
+
.split(/\r?\n/)
|
|
39
|
+
.map((line) => line.trim())
|
|
40
|
+
.filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
41
|
+
};
|
|
42
|
+
const toArray = (value) => {
|
|
43
|
+
if (!value || typeof value === "boolean")
|
|
44
|
+
return [];
|
|
45
|
+
return Array.isArray(value) ? value : [value];
|
|
46
|
+
};
|
|
47
|
+
const readStdinIfProvided = async () => {
|
|
48
|
+
if (process.stdin.isTTY)
|
|
49
|
+
return undefined;
|
|
50
|
+
const chunks = [];
|
|
51
|
+
for await (const chunk of process.stdin) {
|
|
52
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
53
|
+
}
|
|
54
|
+
const input = Buffer.concat(chunks).toString("utf8").trim();
|
|
55
|
+
return input.length ? input : undefined;
|
|
56
|
+
};
|
|
57
|
+
export class AgentRunCommand {
|
|
58
|
+
static async run(argv) {
|
|
59
|
+
const parsed = parseArgs(argv);
|
|
60
|
+
const name = parsed.positionals[0];
|
|
61
|
+
if (!name || parsed.flags.help) {
|
|
62
|
+
throw new Error(USAGE);
|
|
63
|
+
}
|
|
64
|
+
const prompts = [];
|
|
65
|
+
const inlinePrompts = toArray(parsed.flags.prompt);
|
|
66
|
+
for (const prompt of inlinePrompts) {
|
|
67
|
+
const trimmed = prompt.trim();
|
|
68
|
+
if (trimmed)
|
|
69
|
+
prompts.push(trimmed);
|
|
70
|
+
}
|
|
71
|
+
const promptFiles = toArray(parsed.flags["prompt-file"]);
|
|
72
|
+
for (const filePath of promptFiles) {
|
|
73
|
+
const content = await fs.readFile(String(filePath), "utf8");
|
|
74
|
+
const trimmed = content.trim();
|
|
75
|
+
if (trimmed)
|
|
76
|
+
prompts.push(trimmed);
|
|
77
|
+
}
|
|
78
|
+
const taskFiles = toArray(parsed.flags["task-file"]);
|
|
79
|
+
for (const filePath of taskFiles) {
|
|
80
|
+
const entries = await readTaskFile(String(filePath));
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
if (entry)
|
|
83
|
+
prompts.push(entry);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (prompts.length === 0) {
|
|
87
|
+
const stdinPrompt = await readStdinIfProvided();
|
|
88
|
+
if (stdinPrompt)
|
|
89
|
+
prompts.push(stdinPrompt);
|
|
90
|
+
}
|
|
91
|
+
if (prompts.length === 0) {
|
|
92
|
+
throw new Error("agent-run: at least one prompt is required via --prompt, --prompt-file, --task-file, or stdin");
|
|
93
|
+
}
|
|
94
|
+
const api = await AgentsApi.create();
|
|
95
|
+
try {
|
|
96
|
+
const result = await api.runAgent(name, prompts);
|
|
97
|
+
if (parsed.flags.json) {
|
|
98
|
+
// eslint-disable-next-line no-console
|
|
99
|
+
console.log(JSON.stringify({
|
|
100
|
+
agent: result.agent,
|
|
101
|
+
responses: result.responses.map((response, index) => ({
|
|
102
|
+
prompt: result.prompts[index],
|
|
103
|
+
output: response.output,
|
|
104
|
+
adapter: response.adapter,
|
|
105
|
+
model: response.model,
|
|
106
|
+
metadata: response.metadata,
|
|
107
|
+
})),
|
|
108
|
+
}, null, 2));
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
// eslint-disable-next-line no-console
|
|
112
|
+
console.log(`Agent ${result.agent.slug} responded to ${result.responses.length} prompt(s).`);
|
|
113
|
+
result.responses.forEach((response, index) => {
|
|
114
|
+
const label = `${response.adapter}${response.model ? `:${response.model}` : ""}`;
|
|
115
|
+
// eslint-disable-next-line no-console
|
|
116
|
+
console.log(`\n--- Prompt ${index + 1} ---\n${result.prompts[index]}`);
|
|
117
|
+
// eslint-disable-next-line no-console
|
|
118
|
+
console.log(`--- Response ${index + 1} (${label}) ---\n${response.output}`);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
await api.close();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentsCommands.d.ts","sourceRoot":"","sources":["../../../src/commands/agents/AgentsCommands.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AgentsCommands.d.ts","sourceRoot":"","sources":["../../../src/commands/agents/AgentsCommands.ts"],"names":[],"mappings":"AAiNA,qBAAa,cAAc;WACZ,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAkNhD"}
|
|
@@ -38,7 +38,7 @@ const readSecret = async (promptText) => new Promise((resolve) => {
|
|
|
38
38
|
});
|
|
39
39
|
});
|
|
40
40
|
const USAGE = `
|
|
41
|
-
Usage: mcoda agent <list|add|update|delete|remove|auth|auth-status|set-default|use> ...
|
|
41
|
+
Usage: mcoda agent <list|add|update|delete|remove|auth|auth-status|set-default|use|ratings> ...
|
|
42
42
|
|
|
43
43
|
Subcommands:
|
|
44
44
|
list List agents (supports --json)
|
|
@@ -63,6 +63,9 @@ Subcommands:
|
|
|
63
63
|
auth-status <NAME> Show redacted auth status (supports --json)
|
|
64
64
|
set-default|use <NAME> Set workspace default agent (use --workspace to override detection)
|
|
65
65
|
--workspace <PATH> Workspace root to bind defaults
|
|
66
|
+
ratings Show recent rating runs
|
|
67
|
+
--agent <NAME> Agent slug/id (required)
|
|
68
|
+
--last <N> Number of runs (default 50)
|
|
66
69
|
--json Emit JSON for supported commands
|
|
67
70
|
--help Show this help
|
|
68
71
|
`.trim();
|
|
@@ -170,6 +173,16 @@ const formatCost = (value) => {
|
|
|
170
173
|
return "-";
|
|
171
174
|
return Number(value).toFixed(2);
|
|
172
175
|
};
|
|
176
|
+
const formatNumber = (value) => {
|
|
177
|
+
if (value === undefined || value === null || Number.isNaN(value))
|
|
178
|
+
return "-";
|
|
179
|
+
return `${value}`;
|
|
180
|
+
};
|
|
181
|
+
const formatDuration = (value) => {
|
|
182
|
+
if (value === undefined || value === null || Number.isNaN(value))
|
|
183
|
+
return "-";
|
|
184
|
+
return `${Number(value).toFixed(1)}s`;
|
|
185
|
+
};
|
|
173
186
|
const formatCapabilities = (caps) => {
|
|
174
187
|
const list = (caps ?? []).slice().sort();
|
|
175
188
|
if (list.length === 0)
|
|
@@ -365,6 +378,43 @@ export class AgentsCommands {
|
|
|
365
378
|
console.log(`Default agent set to ${name} for workspace ${workspace.workspaceRoot}`);
|
|
366
379
|
break;
|
|
367
380
|
}
|
|
381
|
+
case "ratings": {
|
|
382
|
+
const agentName = parsed.flags.agent ? String(parsed.flags.agent) : parsed.positionals[0];
|
|
383
|
+
if (!agentName)
|
|
384
|
+
throw new Error("Usage: mcoda agent ratings --agent <NAME> [--last <N>] [--json]");
|
|
385
|
+
const lastRaw = parsed.flags.last ?? parsed.flags.limit;
|
|
386
|
+
const last = lastRaw !== undefined ? Number.parseInt(String(lastRaw), 10) : 50;
|
|
387
|
+
if (Number.isNaN(last) || last <= 0) {
|
|
388
|
+
throw new Error("Invalid --last; expected a positive number");
|
|
389
|
+
}
|
|
390
|
+
const ratings = await api.listAgentRunRatings(agentName, last);
|
|
391
|
+
if (parsed.flags.json) {
|
|
392
|
+
// eslint-disable-next-line no-console
|
|
393
|
+
console.log(JSON.stringify(ratings, null, 2));
|
|
394
|
+
}
|
|
395
|
+
else if (ratings.length === 0) {
|
|
396
|
+
// eslint-disable-next-line no-console
|
|
397
|
+
console.log(`No ratings found for ${agentName}.`);
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
const headers = ["CREATED", "COMMAND", "TASK", "SCORE", "QUALITY", "TOKENS", "DURATION", "ITER", "COST"];
|
|
401
|
+
const maxWidths = [16, 18, 24, 6, 7, 8, 9, 6, 8];
|
|
402
|
+
const rows = ratings.map((row) => [
|
|
403
|
+
formatDate(row.createdAt),
|
|
404
|
+
row.commandName ?? "-",
|
|
405
|
+
row.taskKey ?? row.taskId ?? "-",
|
|
406
|
+
formatNumber(row.runScore),
|
|
407
|
+
formatNumber(row.qualityScore),
|
|
408
|
+
formatNumber(row.tokensTotal),
|
|
409
|
+
formatDuration(row.durationSeconds),
|
|
410
|
+
formatNumber(row.iterations),
|
|
411
|
+
formatCost(row.totalCost ?? undefined),
|
|
412
|
+
]);
|
|
413
|
+
// eslint-disable-next-line no-console
|
|
414
|
+
console.log(formatBoxTable(headers, rows, maxWidths));
|
|
415
|
+
}
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
368
418
|
default:
|
|
369
419
|
throw new Error(`Unknown agent subcommand: ${subcommand}`);
|
|
370
420
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GatewayAgentCommand.d.ts","sourceRoot":"","sources":["../../../src/commands/agents/GatewayAgentCommand.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GatewayAgentCommand.d.ts","sourceRoot":"","sources":["../../../src/commands/agents/GatewayAgentCommand.ts"],"names":[],"mappings":"AA+WA,qBAAa,mBAAmB;WACjB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAoMhD"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { GatewayAgentService, WorkspaceResolver, } from "@mcoda/core";
|
|
3
|
+
import { GatewayAgentService, buildGatewayHandoffContent, withGatewayHandoff, writeGatewayHandoffFile, WorkspaceResolver, } from "@mcoda/core";
|
|
4
4
|
import { canonicalizeCommandName } from "@mcoda/shared";
|
|
5
5
|
import { CreateTasksCommand } from "../planning/CreateTasksCommand.js";
|
|
6
6
|
import { RefineTasksCommand } from "../planning/RefineTasksCommand.js";
|
|
@@ -18,10 +18,10 @@ const usage = `mcoda gateway-agent <job> \\
|
|
|
18
18
|
[--gateway-agent <NAME>] \\
|
|
19
19
|
[--max-docs <N>] \\
|
|
20
20
|
[--agent-stream <true|false>] \\
|
|
21
|
+
[--rate-agents] \\
|
|
21
22
|
[--no-offload] \\
|
|
22
23
|
[--json] \\
|
|
23
24
|
[--] [job args...]`;
|
|
24
|
-
const HANDOFF_ENV_PATH = "MCODA_GATEWAY_HANDOFF_PATH";
|
|
25
25
|
const DOC_ONLY_JOBS = new Set(["sds", "openapi-from-docs"]);
|
|
26
26
|
const parseBooleanFlag = (value, defaultValue) => {
|
|
27
27
|
if (value === undefined)
|
|
@@ -40,71 +40,6 @@ const isIoEnabled = () => {
|
|
|
40
40
|
const normalized = raw.trim().toLowerCase();
|
|
41
41
|
return !["0", "false", "off", "no"].includes(normalized);
|
|
42
42
|
};
|
|
43
|
-
const buildHandoffContent = (result) => {
|
|
44
|
-
const lines = [];
|
|
45
|
-
lines.push(`# Gateway Handoff`);
|
|
46
|
-
lines.push("");
|
|
47
|
-
lines.push(`Job: ${result.job}`);
|
|
48
|
-
lines.push(`Gateway agent: ${result.gatewayAgent.slug}`);
|
|
49
|
-
lines.push(`Chosen agent: ${result.chosenAgent.agentSlug}`);
|
|
50
|
-
lines.push("");
|
|
51
|
-
if (result.analysis.reasoningSummary?.trim()) {
|
|
52
|
-
lines.push("## Reasoning Summary");
|
|
53
|
-
lines.push(result.analysis.reasoningSummary.trim());
|
|
54
|
-
lines.push("");
|
|
55
|
-
}
|
|
56
|
-
lines.push("## Summary");
|
|
57
|
-
lines.push(result.analysis.summary || "(none)");
|
|
58
|
-
lines.push("");
|
|
59
|
-
lines.push("## Current State");
|
|
60
|
-
lines.push(result.analysis.currentState || "(none)");
|
|
61
|
-
lines.push("");
|
|
62
|
-
lines.push("## Todo");
|
|
63
|
-
lines.push(result.analysis.todo || "(none)");
|
|
64
|
-
lines.push("");
|
|
65
|
-
lines.push("## Understanding");
|
|
66
|
-
lines.push(result.analysis.understanding || "(none)");
|
|
67
|
-
lines.push("");
|
|
68
|
-
lines.push("## Plan");
|
|
69
|
-
if (result.analysis.plan.length) {
|
|
70
|
-
result.analysis.plan.forEach((step, idx) => lines.push(`${idx + 1}. ${step}`));
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
lines.push("(none)");
|
|
74
|
-
}
|
|
75
|
-
lines.push("");
|
|
76
|
-
lines.push("## Files Likely Touched");
|
|
77
|
-
if (result.analysis.filesLikelyTouched.length) {
|
|
78
|
-
result.analysis.filesLikelyTouched.forEach((file) => lines.push(`- ${file}`));
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
lines.push("(none)");
|
|
82
|
-
}
|
|
83
|
-
lines.push("");
|
|
84
|
-
lines.push("## Files To Create");
|
|
85
|
-
if (result.analysis.filesToCreate.length) {
|
|
86
|
-
result.analysis.filesToCreate.forEach((file) => lines.push(`- ${file}`));
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
lines.push("(none)");
|
|
90
|
-
}
|
|
91
|
-
if (result.analysis.assumptions.length) {
|
|
92
|
-
lines.push("");
|
|
93
|
-
lines.push("## Assumptions");
|
|
94
|
-
result.analysis.assumptions.forEach((item) => lines.push(`- ${item}`));
|
|
95
|
-
}
|
|
96
|
-
if (result.analysis.risks.length) {
|
|
97
|
-
lines.push("");
|
|
98
|
-
lines.push("## Risks");
|
|
99
|
-
result.analysis.risks.forEach((item) => lines.push(`- ${item}`));
|
|
100
|
-
}
|
|
101
|
-
if (result.analysis.docdexNotes.length) {
|
|
102
|
-
lines.push("");
|
|
103
|
-
lines.push("## Docdex Notes");
|
|
104
|
-
result.analysis.docdexNotes.forEach((item) => lines.push(`- ${item}`));
|
|
105
|
-
}
|
|
106
|
-
return lines.join("\n");
|
|
107
|
-
};
|
|
108
43
|
const isSameAgent = (result) => result.chosenAgent.agentId === result.gatewayAgent.id || result.chosenAgent.agentSlug === result.gatewayAgent.slug;
|
|
109
44
|
const collectOffloadBlockers = (result) => {
|
|
110
45
|
const blockers = [];
|
|
@@ -141,7 +76,7 @@ const collectOffloadBlockers = (result) => {
|
|
|
141
76
|
return blockers;
|
|
142
77
|
};
|
|
143
78
|
const parseGatewayArgs = (argv) => {
|
|
144
|
-
const args = { noOffload: false, json: false };
|
|
79
|
+
const args = { noOffload: false, rateAgents: false, json: false };
|
|
145
80
|
for (let i = 0; i < argv.length; i += 1) {
|
|
146
81
|
const arg = argv[i];
|
|
147
82
|
if (arg.startsWith("--workspace=") || arg.startsWith("--workspace-root=")) {
|
|
@@ -173,6 +108,10 @@ const parseGatewayArgs = (argv) => {
|
|
|
173
108
|
args.agentStream = parseBooleanFlag(arg.split("=", 2)[1], true);
|
|
174
109
|
continue;
|
|
175
110
|
}
|
|
111
|
+
if (arg.startsWith("--rate-agents=")) {
|
|
112
|
+
args.rateAgents = parseBooleanFlag(arg.split("=", 2)[1], true);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
176
115
|
switch (arg) {
|
|
177
116
|
case "--workspace":
|
|
178
117
|
case "--workspace-root":
|
|
@@ -211,6 +150,17 @@ const parseGatewayArgs = (argv) => {
|
|
|
211
150
|
}
|
|
212
151
|
break;
|
|
213
152
|
}
|
|
153
|
+
case "--rate-agents": {
|
|
154
|
+
const next = argv[i + 1];
|
|
155
|
+
if (next && !next.startsWith("-")) {
|
|
156
|
+
args.rateAgents = parseBooleanFlag(next, true);
|
|
157
|
+
i += 1;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
args.rateAgents = true;
|
|
161
|
+
}
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
214
164
|
case "--no-offload":
|
|
215
165
|
case "--plan-only":
|
|
216
166
|
args.noOffload = true;
|
|
@@ -472,6 +422,7 @@ export class GatewayAgentCommand {
|
|
|
472
422
|
maxDocs: gatewayArgs.maxDocs,
|
|
473
423
|
agentStream: streamEnabled,
|
|
474
424
|
onStreamChunk,
|
|
425
|
+
rateAgents: gatewayArgs.rateAgents,
|
|
475
426
|
});
|
|
476
427
|
if (shouldPrintStream && streamStarted && !streamEndedWithNewline) {
|
|
477
428
|
process.stdout.write("\n");
|
|
@@ -538,13 +489,6 @@ export class GatewayAgentCommand {
|
|
|
538
489
|
process.exitCode = 1;
|
|
539
490
|
return;
|
|
540
491
|
}
|
|
541
|
-
const handoffContent = buildHandoffContent(result);
|
|
542
|
-
const handoffDir = path.join(workspace.workspaceRoot, ".mcoda", "handoffs");
|
|
543
|
-
await fs.mkdir(handoffDir, { recursive: true });
|
|
544
|
-
const handoffPath = path.join(handoffDir, `gateway-${result.commandRunId}.md`);
|
|
545
|
-
await fs.writeFile(handoffPath, handoffContent, "utf8");
|
|
546
|
-
const previousHandoff = process.env[HANDOFF_ENV_PATH];
|
|
547
|
-
process.env[HANDOFF_ENV_PATH] = handoffPath;
|
|
548
492
|
const forwarded = stripAgentArgs(jobArgs);
|
|
549
493
|
const hasAgentStream = forwarded.some((arg) => arg === "--agent-stream" || arg.startsWith("--agent-stream="));
|
|
550
494
|
const argsWithAgent = [...forwarded];
|
|
@@ -553,22 +497,16 @@ export class GatewayAgentCommand {
|
|
|
553
497
|
}
|
|
554
498
|
argsWithAgent.push("--agent", result.chosenAgent.agentSlug);
|
|
555
499
|
const sameAgent = isSameAgent(result);
|
|
500
|
+
const handoffContent = buildGatewayHandoffContent(result);
|
|
501
|
+
const handoffPath = await writeGatewayHandoffFile(workspace.workspaceRoot, result.commandRunId, handoffContent);
|
|
556
502
|
const actionLabel = sameAgent
|
|
557
503
|
? `Continuing ${result.job} with gateway agent ${result.gatewayAgent.slug}`
|
|
558
504
|
: `Offloading ${result.job} to ${result.chosenAgent.agentSlug}`;
|
|
559
505
|
// eslint-disable-next-line no-console
|
|
560
506
|
console.log(`\n${actionLabel}...`);
|
|
561
|
-
|
|
507
|
+
await withGatewayHandoff(handoffPath, async () => {
|
|
562
508
|
await runner(argsWithAgent);
|
|
563
|
-
}
|
|
564
|
-
finally {
|
|
565
|
-
if (previousHandoff === undefined) {
|
|
566
|
-
delete process.env[HANDOFF_ENV_PATH];
|
|
567
|
-
}
|
|
568
|
-
else {
|
|
569
|
-
process.env[HANDOFF_ENV_PATH] = previousHandoff;
|
|
570
|
-
}
|
|
571
|
-
}
|
|
509
|
+
});
|
|
572
510
|
}
|
|
573
511
|
catch (error) {
|
|
574
512
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrderTasksCommand.d.ts","sourceRoot":"","sources":["../../../src/commands/backlog/OrderTasksCommand.ts"],"names":[],"mappings":"AAGA,UAAU,UAAU;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,EAAE,OAAO,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"OrderTasksCommand.d.ts","sourceRoot":"","sources":["../../../src/commands/backlog/OrderTasksCommand.ts"],"names":[],"mappings":"AAGA,UAAU,UAAU;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;CACf;AA8BD,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,EAAE,KAAG,UAuFpD,CAAC;AA4EF,qBAAa,iBAAiB;WACf,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA+ChD"}
|
|
@@ -8,6 +8,7 @@ const usage = `mcoda order-tasks \\
|
|
|
8
8
|
[--include-blocked] \\
|
|
9
9
|
[--agent <NAME>] \\
|
|
10
10
|
[--agent-stream <true|false>] \\
|
|
11
|
+
[--rate-agents] \\
|
|
11
12
|
[--json]`;
|
|
12
13
|
const parseBooleanFlag = (value, defaultValue) => {
|
|
13
14
|
if (value === undefined)
|
|
@@ -31,6 +32,7 @@ const parseStatuses = (value) => {
|
|
|
31
32
|
export const parseOrderTasksArgs = (argv) => {
|
|
32
33
|
const parsed = {
|
|
33
34
|
includeBlocked: false,
|
|
35
|
+
rateAgents: false,
|
|
34
36
|
json: false,
|
|
35
37
|
};
|
|
36
38
|
for (let i = 0; i < argv.length; i += 1) {
|
|
@@ -43,6 +45,10 @@ export const parseOrderTasksArgs = (argv) => {
|
|
|
43
45
|
parsed.agentStream = parseBooleanFlag(arg.split("=")[1], true);
|
|
44
46
|
continue;
|
|
45
47
|
}
|
|
48
|
+
if (arg.startsWith("--rate-agents=")) {
|
|
49
|
+
parsed.rateAgents = parseBooleanFlag(arg.split("=")[1], true);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
46
52
|
switch (arg) {
|
|
47
53
|
case "--workspace-root":
|
|
48
54
|
parsed.workspaceRoot = argv[i + 1] ? path.resolve(argv[i + 1]) : undefined;
|
|
@@ -78,6 +84,17 @@ export const parseOrderTasksArgs = (argv) => {
|
|
|
78
84
|
}
|
|
79
85
|
break;
|
|
80
86
|
}
|
|
87
|
+
case "--rate-agents": {
|
|
88
|
+
const next = argv[i + 1];
|
|
89
|
+
if (next && !next.startsWith("-")) {
|
|
90
|
+
parsed.rateAgents = parseBooleanFlag(next, true);
|
|
91
|
+
i += 1;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
parsed.rateAgents = true;
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
81
98
|
case "--json":
|
|
82
99
|
parsed.json = true;
|
|
83
100
|
break;
|
|
@@ -180,6 +197,7 @@ export class OrderTasksCommand {
|
|
|
180
197
|
includeBlocked: parsed.includeBlocked,
|
|
181
198
|
agentName: parsed.agentName,
|
|
182
199
|
agentStream: parsed.agentStream,
|
|
200
|
+
rateAgents: parsed.rateAgents,
|
|
183
201
|
});
|
|
184
202
|
if (parsed.json) {
|
|
185
203
|
const payload = {
|
|
@@ -6,6 +6,8 @@ export interface ParsedPdrArgs {
|
|
|
6
6
|
outPath?: string;
|
|
7
7
|
agentName?: string;
|
|
8
8
|
agentStream: boolean;
|
|
9
|
+
rateAgents: boolean;
|
|
10
|
+
fast: boolean;
|
|
9
11
|
dryRun: boolean;
|
|
10
12
|
json: boolean;
|
|
11
13
|
quiet: boolean;
|
|
@@ -20,6 +22,8 @@ export interface ParsedSdsArgs {
|
|
|
20
22
|
agentName?: string;
|
|
21
23
|
templateName?: string;
|
|
22
24
|
agentStream: boolean;
|
|
25
|
+
rateAgents: boolean;
|
|
26
|
+
fast: boolean;
|
|
23
27
|
force: boolean;
|
|
24
28
|
resumeJobId?: string;
|
|
25
29
|
dryRun: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocsCommands.d.ts","sourceRoot":"","sources":["../../../src/commands/docs/DocsCommands.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAUD,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,KAAG,
|
|
1
|
+
{"version":3,"file":"DocsCommands.d.ts","sourceRoot":"","sources":["../../../src/commands/docs/DocsCommands.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAUD,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,KAAG,aAwH7C,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,KAAG,aAwH7C,CAAC;AASF,qBAAa,YAAY;WACV,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAiKhD"}
|