mcoda 0.1.41 → 0.1.43

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.
@@ -1 +1 @@
1
- {"version":3,"file":"McodaEntrypoint.d.ts","sourceRoot":"","sources":["../../src/bin/McodaEntrypoint.ts"],"names":[],"mappings":";AAoCA,qBAAa,eAAe;WACb,GAAG,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;CA6OxE"}
1
+ {"version":3,"file":"McodaEntrypoint.d.ts","sourceRoot":"","sources":["../../src/bin/McodaEntrypoint.ts"],"names":[],"mappings":";AAqCA,qBAAa,eAAe;WACb,GAAG,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;CAuPxE"}
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'node:url';
4
4
  import packageJson from '../../package.json' with { type: 'json' };
5
5
  import { AgentsCommands } from '../commands/agents/AgentsCommands.js';
6
6
  import { CloudCommands } from '../commands/cloud/CloudCommands.js';
7
+ import { SelfHostedCommands } from '../commands/self-hosted/SelfHostedCommands.js';
7
8
  import { ConfigCommands } from '../commands/config/ConfigCommands.js';
8
9
  import { ConsentCommands } from '../commands/consent/ConsentCommands.js';
9
10
  import { GatewayAgentCommand } from '../commands/agents/GatewayAgentCommand.js';
@@ -88,12 +89,14 @@ export class McodaEntrypoint {
88
89
  return;
89
90
  }
90
91
  if (!command) {
91
- throw new Error('Usage: mcoda <agent|cloud|cloud-agent|config|consent|setup|gateway-agent|test-agent|agent-run|routing|docs|openapi|job|jobs|tokens|telemetry|create-tasks|migrate-tasks|refine-tasks|task-sufficiency-audit|sds-preflight|order-tasks|tasks|add-tests|work-on-tasks|gateway-trio|code-review|qa-tasks|backlog|task|task-detail|estimate|update|set-workspace|project-guidance|pdr|sds> [...args]\n' +
92
+ throw new Error('Usage: mcoda <agent|cloud|cloud-agent|self-hosted|self-hosted-agent|config|consent|setup|gateway-agent|test-agent|agent-run|routing|docs|openapi|job|jobs|tokens|telemetry|create-tasks|migrate-tasks|refine-tasks|task-sufficiency-audit|sds-preflight|order-tasks|tasks|add-tests|work-on-tasks|gateway-trio|code-review|qa-tasks|backlog|task|task-detail|estimate|update|set-workspace|project-guidance|pdr|sds> [...args]\n' +
92
93
  'Setup: use `mcoda setup` after installation (or accept the postinstall prompt) to complete the mandatory mswarm telemetry consent flow.\n' +
93
94
  'Config: use `mcoda config set mswarm-api-key <KEY>` to persist an encrypted mswarm API key in the resolved global mcoda config file.\n' +
94
95
  'Consent: use `mcoda consent accept` before other commands if you need to complete consent outside the guided setup flow.\n' +
95
96
  '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' +
96
97
  'Cloud agents: use `mcoda cloud agent list|details|sync` to discover and materialize mswarm-managed remote agents.\n' +
98
+ 'Self-hosted agents: use `mcoda self-hosted agent list|details|sync` to discover and materialize owner-hosted mswarm agents.\n' +
99
+ 'Expose this machine: install `@mcoda/mswarm`, then run `mswarm setup --api-key <KEY>`.\n' +
97
100
  'Aliases: `tasks order-by-deps` forwards to `order-tasks` (dependency-aware ordering), `task`/`task-detail` show a single task.\n' +
98
101
  'Job commands (mcoda job --help for details): list|status|watch|logs|inspect|resume|cancel|tokens\n' +
99
102
  'Jobs API required for job commands (set MCODA_API_BASE_URL/MCODA_JOBS_API_URL or workspace api.baseUrl). status/watch/logs exit non-zero on failed/cancelled jobs per SDS.');
@@ -114,6 +117,10 @@ export class McodaEntrypoint {
114
117
  await CloudCommands.run(rest);
115
118
  return;
116
119
  }
120
+ if (command === 'self-hosted' || command === 'selfhosted') {
121
+ await SelfHostedCommands.run(rest);
122
+ return;
123
+ }
117
124
  if (command === 'config') {
118
125
  await ConfigCommands.run(rest);
119
126
  return;
@@ -130,6 +137,10 @@ export class McodaEntrypoint {
130
137
  await CloudCommands.run(['agent', ...rest]);
131
138
  return;
132
139
  }
140
+ if (command === 'self-hosted-agent' || command === 'selfhosted-agent') {
141
+ await SelfHostedCommands.run(['agent', ...rest]);
142
+ return;
143
+ }
133
144
  if (command === 'gateway-agent') {
134
145
  await GatewayAgentCommand.run(rest);
135
146
  return;
@@ -29,6 +29,6 @@ export class ConfigCommands {
29
29
  await store.saveApiKey(value);
30
30
  const refresh = await MswarmApi.refreshManagedAgentAuth(value);
31
31
  // eslint-disable-next-line no-console
32
- console.log(`Saved encrypted mswarm API key to ${store.configPath()}. Refreshed managed cloud-agent auth for ${refresh.updated} agents.`);
32
+ console.log(`Saved encrypted mswarm API key to ${store.configPath()}. Refreshed managed mswarm-agent auth for ${refresh.updated} agents.`);
33
33
  }
34
34
  }
@@ -0,0 +1,4 @@
1
+ export declare class SelfHostedCommands {
2
+ static run(argv: string[]): Promise<void>;
3
+ }
4
+ //# sourceMappingURL=SelfHostedCommands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelfHostedCommands.d.ts","sourceRoot":"","sources":["../../../src/commands/self-hosted/SelfHostedCommands.ts"],"names":[],"mappings":"AA6NA,qBAAa,kBAAkB;WAChB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA8FhD"}
@@ -0,0 +1,283 @@
1
+ import { MswarmApi, } from "@mcoda/core";
2
+ const USAGE = `
3
+ Usage: mcoda self-hosted agent <list|details|sync> [options]
4
+
5
+ Subcommands:
6
+ agent list List mswarm self-hosted agents (supports --json)
7
+ --provider <NAME> Filter by provider (mcoda|ollama)
8
+ --limit <N> Limit returned agents
9
+ --include-unreachable Include unreachable agents in the catalog result
10
+ --max-cost-per-1m-token <N>
11
+ Exclude agents above the given cost_per_million
12
+ --sorted-by-catalog-rating
13
+ Sort results by the catalog rating field (descending)
14
+ --min-context <N> Require at least this context window
15
+ --min-reasoning <N> Require at least this reasoning rating
16
+ agent details <SLUG> Show a single mswarm self-hosted agent (supports --json)
17
+ agent sync Sync self-hosted agents into the local mcoda registry
18
+ --provider <NAME> Filter by provider before syncing
19
+ --include-unreachable Sync unreachable agents too
20
+ --limit <N> Limit synced agents
21
+ --prune Remove previously synced self-hosted agents missing from the current catalog result
22
+ --agent-slug-prefix <P> Override the local managed-agent slug prefix
23
+
24
+ Connection options:
25
+ --base-url <URL> Override MCODA_MSWARM_BASE_URL (default: https://api.mswarm.org/)
26
+ --openai-base-url <URL> Override execution base URL for synced managed-agent execution
27
+ --api-key <KEY> Override MCODA_MSWARM_API_KEY
28
+ --timeout-ms <N> Override MCODA_MSWARM_TIMEOUT_MS
29
+
30
+ Environment:
31
+ MCODA_MSWARM_BASE_URL
32
+ MCODA_MSWARM_OPENAI_BASE_URL
33
+ MCODA_MSWARM_API_KEY
34
+ MCODA_MSWARM_TIMEOUT_MS
35
+ MCODA_MSWARM_SELF_HOSTED_AGENT_SLUG_PREFIX
36
+ Or persist the API key with: mcoda config set mswarm-api-key <KEY>
37
+
38
+ To expose this machine's local agents:
39
+ npm install -g @mcoda/mswarm
40
+ mswarm setup --api-key <KEY>
41
+
42
+ Flags:
43
+ --json Emit JSON for supported commands
44
+ --help Show this help
45
+ `.trim();
46
+ const parseArgs = (argv) => {
47
+ const flags = {};
48
+ const positionals = [];
49
+ for (let index = 0; index < argv.length; index += 1) {
50
+ const arg = argv[index];
51
+ if (arg.startsWith("--")) {
52
+ const key = arg.replace(/^--/, "");
53
+ const next = argv[index + 1];
54
+ if (next && !next.startsWith("--")) {
55
+ const current = flags[key];
56
+ if (current === undefined) {
57
+ flags[key] = next;
58
+ }
59
+ else if (Array.isArray(current)) {
60
+ flags[key] = [...current, next];
61
+ }
62
+ else if (typeof current === "string") {
63
+ flags[key] = [current, next];
64
+ }
65
+ else {
66
+ flags[key] = [next];
67
+ }
68
+ index += 1;
69
+ }
70
+ else {
71
+ flags[key] = true;
72
+ }
73
+ continue;
74
+ }
75
+ positionals.push(arg);
76
+ }
77
+ return { flags, positionals };
78
+ };
79
+ const resolveString = (value) => {
80
+ if (value === undefined || typeof value === "boolean")
81
+ return undefined;
82
+ return Array.isArray(value) ? value[value.length - 1] : value;
83
+ };
84
+ const resolvePositiveInt = (value, label) => {
85
+ const raw = resolveString(value);
86
+ if (raw === undefined)
87
+ return undefined;
88
+ const parsed = Number.parseInt(raw, 10);
89
+ if (!Number.isFinite(parsed) || parsed <= 0) {
90
+ throw new Error(`Invalid ${label}; expected a positive integer`);
91
+ }
92
+ return parsed;
93
+ };
94
+ const resolveNonNegativeNumber = (value, label) => {
95
+ const raw = resolveString(value);
96
+ if (raw === undefined)
97
+ return undefined;
98
+ const parsed = Number(raw);
99
+ if (!Number.isFinite(parsed) || parsed < 0) {
100
+ throw new Error(`Invalid ${label}; expected a non-negative number`);
101
+ }
102
+ return parsed;
103
+ };
104
+ const formatNumber = (value) => value === undefined || Number.isNaN(value) ? "-" : String(value);
105
+ const formatCapabilities = (capabilities) => capabilities && capabilities.length > 0 ? capabilities.join(",") : "-";
106
+ const formatBoolean = (value) => value === undefined ? "-" : value ? "yes" : "no";
107
+ const pad = (value, width) => value.padEnd(width, " ");
108
+ const renderTable = (headers, rows) => {
109
+ const widths = headers.map((header, columnIndex) => Math.max(header.length, ...rows.map((row) => row[columnIndex]?.length ?? 0)));
110
+ const lines = [
111
+ headers.map((header, index) => pad(header, widths[index] ?? header.length)).join(" "),
112
+ widths.map((width) => "-".repeat(width)).join(" "),
113
+ ...rows.map((row) => row.map((cell, index) => pad(cell, widths[index] ?? cell.length)).join(" ")),
114
+ ];
115
+ return lines.join("\n");
116
+ };
117
+ const printAgentList = (agents) => {
118
+ if (agents.length === 0) {
119
+ // eslint-disable-next-line no-console
120
+ console.log("No self-hosted agents found.");
121
+ return;
122
+ }
123
+ const headers = [
124
+ "REMOTE SLUG",
125
+ "PROVIDER",
126
+ "ADAPTER",
127
+ "MODEL",
128
+ "RATING",
129
+ "REASON",
130
+ "MAX CPLX",
131
+ "CTX",
132
+ "COST/$1M",
133
+ "TOOLS",
134
+ "HEALTH",
135
+ "CAPABILITIES",
136
+ ];
137
+ const rows = agents.map((agent) => [
138
+ agent.remote_slug ?? agent.slug,
139
+ agent.provider,
140
+ agent.adapter ?? "-",
141
+ agent.default_model,
142
+ formatNumber(agent.rating),
143
+ formatNumber(agent.reasoning_rating),
144
+ formatNumber(agent.max_complexity),
145
+ formatNumber(agent.context_window),
146
+ formatNumber(agent.cost_per_million),
147
+ formatBoolean(agent.supports_tools),
148
+ agent.health_status ?? "-",
149
+ formatCapabilities(agent.capabilities),
150
+ ]);
151
+ // eslint-disable-next-line no-console
152
+ console.log(renderTable(headers, rows));
153
+ };
154
+ const printAgentDetails = (agent) => {
155
+ const entries = [
156
+ ["Slug", agent.slug],
157
+ ["Remote slug", agent.remote_slug ?? "-"],
158
+ ["Provider", agent.provider],
159
+ ["Adapter", agent.adapter ?? "-"],
160
+ ["Source agent", agent.source_agent_slug ?? "-"],
161
+ ["Model", agent.default_model],
162
+ ["Model ID", agent.model_id ?? "-"],
163
+ ["Display name", agent.display_name ?? "-"],
164
+ ["Description", agent.description ?? "-"],
165
+ ["Rating", formatNumber(agent.rating)],
166
+ ["Reasoning rating", formatNumber(agent.reasoning_rating)],
167
+ ["Max complexity", formatNumber(agent.max_complexity)],
168
+ ["Cost / 1M tokens", formatNumber(agent.cost_per_million)],
169
+ ["Context window", formatNumber(agent.context_window)],
170
+ ["Supports tools", formatBoolean(agent.supports_tools)],
171
+ ["Supports reasoning", formatBoolean(agent.supports_reasoning)],
172
+ ["Health", agent.health_status ?? "-"],
173
+ ["Capabilities", formatCapabilities(agent.capabilities)],
174
+ ];
175
+ const labelWidth = Math.max(...entries.map(([label]) => label.length));
176
+ for (const [label, value] of entries) {
177
+ // eslint-disable-next-line no-console
178
+ console.log(`${label.padEnd(labelWidth, " ")} : ${value}`);
179
+ }
180
+ };
181
+ const printSyncSummary = (summary) => {
182
+ // eslint-disable-next-line no-console
183
+ console.log(`Synced ${summary.agents.length} self-hosted agents (created=${summary.created}, updated=${summary.updated}, deleted=${summary.deleted}).`);
184
+ if (summary.agents.length === 0)
185
+ return;
186
+ const rows = summary.agents.map((record) => [
187
+ record.remoteSlug,
188
+ record.localSlug,
189
+ record.action,
190
+ record.provider,
191
+ record.defaultModel,
192
+ ]);
193
+ // eslint-disable-next-line no-console
194
+ console.log(renderTable(["REMOTE SLUG", "LOCAL SLUG", "ACTION", "PROVIDER", "MODEL"], rows));
195
+ };
196
+ export class SelfHostedCommands {
197
+ static async run(argv) {
198
+ const [topic, rawSubcommand, ...rest] = argv;
199
+ if (!topic || argv.includes("--help") || argv.includes("-h")) {
200
+ // eslint-disable-next-line no-console
201
+ console.log(USAGE);
202
+ return;
203
+ }
204
+ if (topic !== "agent" && topic !== "agents") {
205
+ throw new Error(`Unknown self-hosted topic: ${topic}`);
206
+ }
207
+ const subcommand = rawSubcommand === "detail" || rawSubcommand === "show"
208
+ ? "details"
209
+ : rawSubcommand;
210
+ if (!subcommand) {
211
+ // eslint-disable-next-line no-console
212
+ console.log(USAGE);
213
+ return;
214
+ }
215
+ const parsed = parseArgs(rest);
216
+ const api = await MswarmApi.create({
217
+ baseUrl: resolveString(parsed.flags["base-url"]),
218
+ openAiBaseUrl: resolveString(parsed.flags["openai-base-url"]),
219
+ apiKey: resolveString(parsed.flags["api-key"]),
220
+ timeoutMs: resolvePositiveInt(parsed.flags["timeout-ms"], "--timeout-ms"),
221
+ selfHostedAgentSlugPrefix: resolveString(parsed.flags["agent-slug-prefix"]),
222
+ });
223
+ try {
224
+ switch (subcommand) {
225
+ case "list": {
226
+ const agents = await api.listSelfHostedAgents({
227
+ provider: resolveString(parsed.flags.provider),
228
+ limit: resolvePositiveInt(parsed.flags.limit, "--limit"),
229
+ includeUnreachable: Boolean(parsed.flags["include-unreachable"]),
230
+ maxCostPerMillion: resolveNonNegativeNumber(parsed.flags["max-cost-per-1m-token"], "--max-cost-per-1m-token"),
231
+ minContextWindow: resolvePositiveInt(parsed.flags["min-context"], "--min-context"),
232
+ minReasoningRating: resolveNonNegativeNumber(parsed.flags["min-reasoning"], "--min-reasoning"),
233
+ sortByCatalogRating: Boolean(parsed.flags["sorted-by-catalog-rating"] || parsed.flags["sort-by-catalog-rating"]),
234
+ });
235
+ if (parsed.flags.json) {
236
+ // eslint-disable-next-line no-console
237
+ console.log(JSON.stringify(agents, null, 2));
238
+ }
239
+ else {
240
+ printAgentList(agents);
241
+ }
242
+ break;
243
+ }
244
+ case "details": {
245
+ const slug = parsed.positionals[0];
246
+ if (!slug) {
247
+ throw new Error("Usage: mcoda self-hosted agent details <SLUG> [--json]");
248
+ }
249
+ const agent = await api.getSelfHostedAgent(slug);
250
+ if (parsed.flags.json) {
251
+ // eslint-disable-next-line no-console
252
+ console.log(JSON.stringify(agent, null, 2));
253
+ }
254
+ else {
255
+ printAgentDetails(agent);
256
+ }
257
+ break;
258
+ }
259
+ case "sync": {
260
+ const summary = await api.syncSelfHostedAgents({
261
+ provider: resolveString(parsed.flags.provider),
262
+ limit: resolvePositiveInt(parsed.flags.limit, "--limit"),
263
+ includeUnreachable: Boolean(parsed.flags["include-unreachable"]),
264
+ pruneMissing: Boolean(parsed.flags.prune),
265
+ });
266
+ if (parsed.flags.json) {
267
+ // eslint-disable-next-line no-console
268
+ console.log(JSON.stringify(summary, null, 2));
269
+ }
270
+ else {
271
+ printSyncSummary(summary);
272
+ }
273
+ break;
274
+ }
275
+ default:
276
+ throw new Error(`Unknown self-hosted subcommand: ${subcommand}`);
277
+ }
278
+ }
279
+ finally {
280
+ await api.close();
281
+ }
282
+ }
283
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './commands/agents/AgentsCommands.js';
2
2
  export * from './bin/McodaEntrypoint.js';
3
3
  export * from './commands/cloud/CloudCommands.js';
4
+ export * from './commands/self-hosted/SelfHostedCommands.js';
4
5
  export * from './commands/config/ConfigCommands.js';
5
6
  export * from './commands/consent/ConsentCommands.js';
6
7
  export * from './commands/docs/DocsCommands.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAC;AACpD,cAAc,0BAA0B,CAAC;AACzC,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,uCAAuC,CAAC;AACtD,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC;AAChD,cAAc,uCAAuC,CAAC;AACtD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,uCAAuC,CAAC;AACtD,cAAc,wCAAwC,CAAC;AACvD,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC;AACxD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,oDAAoD,CAAC;AACnE,cAAc,4CAA4C,CAAC;AAC3D,cAAc,uCAAuC,CAAC;AACtD,cAAc,uCAAuC,CAAC;AACtD,cAAc,wCAAwC,CAAC;AACvD,cAAc,uCAAuC,CAAC;AACtD,cAAc,qCAAqC,CAAC;AACpD,cAAc,uCAAuC,CAAC;AACtD,cAAc,kCAAkC,CAAC;AACjD,cAAc,uCAAuC,CAAC;AACtD,cAAc,gDAAgD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAC;AACpD,cAAc,0BAA0B,CAAC;AACzC,cAAc,mCAAmC,CAAC;AAClD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,qCAAqC,CAAC;AACpD,cAAc,uCAAuC,CAAC;AACtD,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC;AAChD,cAAc,uCAAuC,CAAC;AACtD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,uCAAuC,CAAC;AACtD,cAAc,wCAAwC,CAAC;AACvD,cAAc,yCAAyC,CAAC;AACxD,cAAc,yCAAyC,CAAC;AACxD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC;AAC1D,cAAc,oDAAoD,CAAC;AACnE,cAAc,4CAA4C,CAAC;AAC3D,cAAc,uCAAuC,CAAC;AACtD,cAAc,uCAAuC,CAAC;AACtD,cAAc,wCAAwC,CAAC;AACvD,cAAc,uCAAuC,CAAC;AACtD,cAAc,qCAAqC,CAAC;AACpD,cAAc,uCAAuC,CAAC;AACtD,cAAc,kCAAkC,CAAC;AACjD,cAAc,uCAAuC,CAAC;AACtD,cAAc,gDAAgD,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './commands/agents/AgentsCommands.js';
2
2
  export * from './bin/McodaEntrypoint.js';
3
3
  export * from './commands/cloud/CloudCommands.js';
4
+ export * from './commands/self-hosted/SelfHostedCommands.js';
4
5
  export * from './commands/config/ConfigCommands.js';
5
6
  export * from './commands/consent/ConsentCommands.js';
6
7
  export * from './commands/docs/DocsCommands.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcoda",
3
- "version": "0.1.41",
3
+ "version": "0.1.43",
4
4
  "description": "Local-first CLI for planning, documentation, and execution workflows with agent assistance.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -47,12 +47,12 @@
47
47
  },
48
48
  "dependencies": {
49
49
  "yaml": "^2.4.2",
50
- "@mcoda/core": "0.1.41",
51
- "@mcoda/shared": "0.1.41"
50
+ "@mcoda/core": "0.1.43",
51
+ "@mcoda/shared": "0.1.43"
52
52
  },
53
53
  "devDependencies": {
54
- "@mcoda/db": "0.1.41",
55
- "@mcoda/integrations": "0.1.41"
54
+ "@mcoda/db": "0.1.43",
55
+ "@mcoda/integrations": "0.1.43"
56
56
  },
57
57
  "scripts": {
58
58
  "build": "tsc -p tsconfig.json",