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.
Files changed (44) hide show
  1. package/CHANGELOG.md +4 -1
  2. package/README.md +35 -0
  3. package/dist/bin/McodaEntrypoint.d.ts.map +1 -1
  4. package/dist/bin/McodaEntrypoint.js +11 -1
  5. package/dist/commands/agents/AgentRunCommand.d.ts +4 -0
  6. package/dist/commands/agents/AgentRunCommand.d.ts.map +1 -0
  7. package/dist/commands/agents/AgentRunCommand.js +126 -0
  8. package/dist/commands/agents/AgentsCommands.d.ts.map +1 -1
  9. package/dist/commands/agents/AgentsCommands.js +51 -1
  10. package/dist/commands/agents/GatewayAgentCommand.d.ts.map +1 -1
  11. package/dist/commands/agents/GatewayAgentCommand.js +23 -85
  12. package/dist/commands/backlog/OrderTasksCommand.d.ts +1 -0
  13. package/dist/commands/backlog/OrderTasksCommand.d.ts.map +1 -1
  14. package/dist/commands/backlog/OrderTasksCommand.js +18 -0
  15. package/dist/commands/docs/DocsCommands.d.ts +4 -0
  16. package/dist/commands/docs/DocsCommands.d.ts.map +1 -1
  17. package/dist/commands/docs/DocsCommands.js +52 -2
  18. package/dist/commands/openapi/OpenapiCommands.d.ts +1 -0
  19. package/dist/commands/openapi/OpenapiCommands.d.ts.map +1 -1
  20. package/dist/commands/openapi/OpenapiCommands.js +20 -1
  21. package/dist/commands/planning/CreateTasksCommand.d.ts +15 -0
  22. package/dist/commands/planning/CreateTasksCommand.d.ts.map +1 -1
  23. package/dist/commands/planning/CreateTasksCommand.js +135 -2
  24. package/dist/commands/planning/QaTasksCommand.d.ts +2 -0
  25. package/dist/commands/planning/QaTasksCommand.d.ts.map +1 -1
  26. package/dist/commands/planning/QaTasksCommand.js +30 -1
  27. package/dist/commands/planning/RefineTasksCommand.d.ts +1 -0
  28. package/dist/commands/planning/RefineTasksCommand.d.ts.map +1 -1
  29. package/dist/commands/planning/RefineTasksCommand.js +20 -1
  30. package/dist/commands/review/CodeReviewCommand.d.ts +1 -0
  31. package/dist/commands/review/CodeReviewCommand.d.ts.map +1 -1
  32. package/dist/commands/review/CodeReviewCommand.js +20 -0
  33. package/dist/commands/work/GatewayTrioCommand.d.ts +42 -0
  34. package/dist/commands/work/GatewayTrioCommand.d.ts.map +1 -0
  35. package/dist/commands/work/GatewayTrioCommand.js +935 -0
  36. package/dist/commands/work/WorkOnTasksCommand.d.ts +3 -0
  37. package/dist/commands/work/WorkOnTasksCommand.d.ts.map +1 -1
  38. package/dist/commands/work/WorkOnTasksCommand.js +72 -0
  39. package/dist/commands/workspace/SetWorkspaceCommand.d.ts.map +1 -1
  40. package/dist/commands/workspace/SetWorkspaceCommand.js +38 -13
  41. package/dist/index.d.ts +1 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +1 -0
  44. package/package.json +5 -5
package/CHANGELOG.md CHANGED
@@ -3,5 +3,8 @@
3
3
  ## Unreleased
4
4
  - Initial npm packaging scaffold for the mcoda CLI.
5
5
 
6
- ## 0.1.7
6
+ ## 0.1.9
7
+ - Release v0.1.9.
8
+
9
+ ## 0.1.8
7
10
  - Initial public release of the mcoda CLI.
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":";AAyBA,qBAAa,eAAe;WACb,GAAG,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;CAoIxE"}
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,4 @@
1
+ export declare class AgentRunCommand {
2
+ static run(argv: string[]): Promise<void>;
3
+ }
4
+ //# sourceMappingURL=AgentRunCommand.d.ts.map
@@ -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":"AAoMA,qBAAa,cAAc;WACZ,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAgLhD"}
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":"AA6ZA,qBAAa,mBAAmB;WACjB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA8MhD"}
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
- try {
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);
@@ -6,6 +6,7 @@ interface ParsedArgs {
6
6
  includeBlocked: boolean;
7
7
  agentName?: string;
8
8
  agentStream?: boolean;
9
+ rateAgents: boolean;
9
10
  json: boolean;
10
11
  }
11
12
  export declare const parseOrderTasksArgs: (argv: string[]) => ParsedArgs;
@@ -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;AA6BD,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,EAAE,KAAG,UAwEpD,CAAC;AA4EF,qBAAa,iBAAiB;WACf,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA8ChD"}
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,aAkG7C,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,KAAG,aAkG7C,CAAC;AASF,qBAAa,YAAY;WACV,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA6JhD"}
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"}