@agnox/mcp-server 0.0.0-stage → 1.0.1
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 +179 -3
- package/dist/bin/agnox.d.ts +2 -0
- package/dist/bin/agnox.js +11 -0
- package/dist/bin/agnox.js.map +1 -0
- package/dist/bin/mcp-server.d.ts +2 -0
- package/dist/bin/mcp-server.js +4 -0
- package/dist/bin/mcp-server.js.map +1 -0
- package/dist/cli.d.ts +24 -0
- package/dist/cli.js +102 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +197 -0
- package/dist/client.js +117 -0
- package/dist/client.js.map +1 -0
- package/dist/commands/context.d.ts +22 -0
- package/dist/commands/context.js +25 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/export-specs.d.ts +11 -0
- package/dist/commands/export-specs.js +85 -0
- package/dist/commands/export-specs.js.map +1 -0
- package/dist/commands/mcp.d.ts +9 -0
- package/dist/commands/mcp.js +29 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/runs.d.ts +6 -0
- package/dist/commands/runs.js +74 -0
- package/dist/commands/runs.js.map +1 -0
- package/dist/commands/trigger.d.ts +7 -0
- package/dist/commands/trigger.js +67 -0
- package/dist/commands/trigger.js.map +1 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.js +44 -0
- package/dist/config.js.map +1 -0
- package/dist/format.d.ts +12 -0
- package/dist/format.js +45 -0
- package/dist/format.js.map +1 -0
- package/dist/mcp/server.d.ts +30 -0
- package/dist/mcp/server.js +144 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +32 -0
- package/dist/mcp/tools.js +229 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/package.json +48 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What every CLI command receives.
|
|
3
|
+
*/
|
|
4
|
+
import type * as fsPromises from 'node:fs/promises';
|
|
5
|
+
import type { AgnoxClient } from '../client.js';
|
|
6
|
+
export type CliFs = Pick<typeof fsPromises, 'mkdir' | 'writeFile' | 'lstat'>;
|
|
7
|
+
export interface ICommandContext {
|
|
8
|
+
client: AgnoxClient;
|
|
9
|
+
/** AGNOX_PROJECT_ID, the default for --project. */
|
|
10
|
+
defaultProjectId?: string;
|
|
11
|
+
stdout(line: string): void;
|
|
12
|
+
stderr(line: string): void;
|
|
13
|
+
cwd: string;
|
|
14
|
+
fs: CliFs;
|
|
15
|
+
sleep(ms: number): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
/** A usage mistake: printed as one line, exit code 1. */
|
|
18
|
+
export declare class UsageError extends Error {
|
|
19
|
+
constructor(message: string);
|
|
20
|
+
}
|
|
21
|
+
export declare function requireProject(ctx: ICommandContext, project: string | undefined): string;
|
|
22
|
+
export declare function parsePositiveInt(value: string | undefined, name: string): number | undefined;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What every CLI command receives.
|
|
3
|
+
*/
|
|
4
|
+
/** A usage mistake: printed as one line, exit code 1. */
|
|
5
|
+
export class UsageError extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = 'UsageError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function requireProject(ctx, project) {
|
|
12
|
+
const projectId = project ?? ctx.defaultProjectId;
|
|
13
|
+
if (!projectId)
|
|
14
|
+
throw new UsageError('No project: pass --project <id> or set AGNOX_PROJECT_ID');
|
|
15
|
+
return projectId;
|
|
16
|
+
}
|
|
17
|
+
export function parsePositiveInt(value, name) {
|
|
18
|
+
if (value === undefined)
|
|
19
|
+
return undefined;
|
|
20
|
+
const parsed = Number(value);
|
|
21
|
+
if (!Number.isInteger(parsed) || parsed < 1)
|
|
22
|
+
throw new UsageError(`${name} must be a positive whole number`);
|
|
23
|
+
return parsed;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"AAAA;;GAEG;AAkBH,yDAAyD;AACzD,MAAM,OAAO,UAAW,SAAQ,KAAK;IACjC,YAAY,OAAe;QACvB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC7B,CAAC;CACJ;AAED,MAAM,UAAU,cAAc,CAAC,GAAoB,EAAE,OAA2B;IAC5E,MAAM,SAAS,GAAG,OAAO,IAAI,GAAG,CAAC,gBAAgB,CAAC;IAClD,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,UAAU,CAAC,yDAAyD,CAAC,CAAC;IAChG,OAAO,SAAS,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAyB,EAAE,IAAY;IACpE,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,GAAG,IAAI,kCAAkC,CAAC,CAAC;IAC7G,OAAO,MAAM,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agnox export-specs --out <dir> [--project <id>] [--folder <path>] [--force]
|
|
3
|
+
*
|
|
4
|
+
* Writes Playwright skeletons for the project's manual test cases, one file per
|
|
5
|
+
* top-level folder. Nothing is written when a file would leave --out, or when a
|
|
6
|
+
* file exists and --force is not given.
|
|
7
|
+
*/
|
|
8
|
+
import { type ICommandContext } from './context.js';
|
|
9
|
+
export declare const MAX_SPEC_FILES = 500;
|
|
10
|
+
export declare const MAX_SPEC_BYTES: number;
|
|
11
|
+
export declare function exportSpecs(args: string[], ctx: ICommandContext): Promise<number>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agnox export-specs --out <dir> [--project <id>] [--folder <path>] [--force]
|
|
3
|
+
*
|
|
4
|
+
* Writes Playwright skeletons for the project's manual test cases, one file per
|
|
5
|
+
* top-level folder. Nothing is written when a file would leave --out, or when a
|
|
6
|
+
* file exists and --force is not given.
|
|
7
|
+
*/
|
|
8
|
+
import { parseArgs } from 'node:util';
|
|
9
|
+
import { isAbsolute, join, relative, resolve } from 'node:path';
|
|
10
|
+
import { sanitizeForTerminal } from '../format.js';
|
|
11
|
+
import { requireProject, UsageError } from './context.js';
|
|
12
|
+
/** Flat, lower-case kebab names only: no directories, dots other than the suffix, colons (NTFS streams) or config files. */
|
|
13
|
+
const SPEC_NAME = /^[a-z0-9-]{1,100}\.spec\.ts$/;
|
|
14
|
+
const WINDOWS_DEVICE_STEM = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/;
|
|
15
|
+
export const MAX_SPEC_FILES = 500;
|
|
16
|
+
export const MAX_SPEC_BYTES = 5 * 1024 * 1024;
|
|
17
|
+
function isAcceptedName(name) {
|
|
18
|
+
return SPEC_NAME.test(name) && !WINDOWS_DEVICE_STEM.test(name.slice(0, -'.spec.ts'.length));
|
|
19
|
+
}
|
|
20
|
+
async function inspect(ctx, path) {
|
|
21
|
+
try {
|
|
22
|
+
return (await ctx.fs.lstat(path)).isSymbolicLink() ? 'symlink' : 'file';
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
if (error?.code === 'ENOENT')
|
|
26
|
+
return 'missing';
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function exportSpecs(args, ctx) {
|
|
31
|
+
const { values } = parseArgs({
|
|
32
|
+
args,
|
|
33
|
+
options: {
|
|
34
|
+
out: { type: 'string' },
|
|
35
|
+
project: { type: 'string' },
|
|
36
|
+
folder: { type: 'string' },
|
|
37
|
+
force: { type: 'boolean', default: false },
|
|
38
|
+
},
|
|
39
|
+
strict: true,
|
|
40
|
+
});
|
|
41
|
+
if (!values.out)
|
|
42
|
+
throw new UsageError('Usage: agnox export-specs --out <dir> [--project <id>] [--folder <path>] [--force]');
|
|
43
|
+
const projectId = requireProject(ctx, values.project);
|
|
44
|
+
const outDir = resolve(ctx.cwd, values.out);
|
|
45
|
+
const { files } = await ctx.client.exportTestCases({
|
|
46
|
+
projectId, format: 'playwright', ...(values.folder ? { folderPath: values.folder } : {}),
|
|
47
|
+
});
|
|
48
|
+
// Validate everything before the first write.
|
|
49
|
+
if (files.length > MAX_SPEC_FILES) {
|
|
50
|
+
throw new UsageError(`Refusing to write ${files.length} files: the limit is ${MAX_SPEC_FILES}`);
|
|
51
|
+
}
|
|
52
|
+
const targets = files.map((file) => {
|
|
53
|
+
if (typeof file.path !== 'string' || !isAcceptedName(file.path)) {
|
|
54
|
+
throw new UsageError(`Refusing to write "${sanitizeForTerminal(String(file.path)).slice(0, 120)}": only flat lower-case *.spec.ts names are accepted`);
|
|
55
|
+
}
|
|
56
|
+
if (typeof file.content !== 'string' || Buffer.byteLength(file.content, 'utf8') > MAX_SPEC_BYTES) {
|
|
57
|
+
throw new UsageError(`Refusing to write "${file.path}": it is larger than ${MAX_SPEC_BYTES / 1024 / 1024} MB`);
|
|
58
|
+
}
|
|
59
|
+
const target = resolve(outDir, file.path);
|
|
60
|
+
const rel = relative(outDir, target);
|
|
61
|
+
if (!rel || rel.startsWith('..') || isAbsolute(rel)) {
|
|
62
|
+
throw new UsageError(`Refusing to write "${file.path}": it is outside ${values.out}`);
|
|
63
|
+
}
|
|
64
|
+
return { target, content: file.content, display: join(values.out, rel) };
|
|
65
|
+
});
|
|
66
|
+
const taken = [];
|
|
67
|
+
for (const t of targets) {
|
|
68
|
+
const state = await inspect(ctx, t.target);
|
|
69
|
+
if (state === 'symlink')
|
|
70
|
+
throw new UsageError(`Refusing to write ${t.display}: it is a symbolic link`);
|
|
71
|
+
if (state === 'file')
|
|
72
|
+
taken.push(t.display);
|
|
73
|
+
}
|
|
74
|
+
if (!values.force && taken.length > 0) {
|
|
75
|
+
throw new UsageError(`${taken.join(', ')} already exist${taken.length === 1 ? 's' : ''}; use --force to overwrite`);
|
|
76
|
+
}
|
|
77
|
+
await ctx.fs.mkdir(outDir, { recursive: true });
|
|
78
|
+
for (const t of targets) {
|
|
79
|
+
await ctx.fs.writeFile(t.target, t.content, 'utf8');
|
|
80
|
+
ctx.stdout(`wrote ${t.display}`);
|
|
81
|
+
}
|
|
82
|
+
ctx.stdout(`Exported ${targets.length} spec file${targets.length === 1 ? '' : 's'} to ${values.out}`);
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=export-specs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-specs.js","sourceRoot":"","sources":["../../src/commands/export-specs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agnox mcp / the mcp-server bin: run the MCP server on stdio.
|
|
3
|
+
*
|
|
4
|
+
* stdout carries protocol messages only. A missing or invalid AGNOX_API_KEY does
|
|
5
|
+
* not stop the server: it still answers initialize and tools/list, and every tool
|
|
6
|
+
* call returns the configuration error so the assistant can tell the person.
|
|
7
|
+
*/
|
|
8
|
+
import type { Readable, Writable } from 'node:stream';
|
|
9
|
+
export declare function startMcpServer(env: Record<string, string | undefined>, input: Readable, output: Writable, stderr: (line: string) => void): Promise<void>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agnox mcp / the mcp-server bin: run the MCP server on stdio.
|
|
3
|
+
*
|
|
4
|
+
* stdout carries protocol messages only. A missing or invalid AGNOX_API_KEY does
|
|
5
|
+
* not stop the server: it still answers initialize and tools/list, and every tool
|
|
6
|
+
* call returns the configuration error so the assistant can tell the person.
|
|
7
|
+
*/
|
|
8
|
+
import { AgnoxClient } from '../client.js';
|
|
9
|
+
import { loadConfig } from '../config.js';
|
|
10
|
+
import { createMcpServer, serveStdio } from '../mcp/server.js';
|
|
11
|
+
export async function startMcpServer(env, input, output, stderr) {
|
|
12
|
+
let client;
|
|
13
|
+
const getClient = () => {
|
|
14
|
+
client ??= new AgnoxClient(loadConfig(env));
|
|
15
|
+
return client;
|
|
16
|
+
};
|
|
17
|
+
try {
|
|
18
|
+
getClient();
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
stderr(`[agnox mcp] ${error instanceof Error ? error.message : String(error)}`);
|
|
22
|
+
}
|
|
23
|
+
const server = createMcpServer(getClient, {
|
|
24
|
+
defaultProjectId: env.AGNOX_PROJECT_ID?.trim() || undefined,
|
|
25
|
+
secrets: env.AGNOX_API_KEY ? [env.AGNOX_API_KEY.trim()] : [],
|
|
26
|
+
});
|
|
27
|
+
await serveStdio(server, input, output);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE/D,MAAM,CAAC,KAAK,UAAU,cAAc,CAChC,GAAuC,EACvC,KAAe,EACf,MAAgB,EAChB,MAA8B;IAE9B,IAAI,MAA+B,CAAC;IACpC,MAAM,SAAS,GAAG,GAAgB,EAAE;QAChC,MAAM,KAAK,IAAI,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5C,OAAO,MAAM,CAAC;IAClB,CAAC,CAAC;IACF,IAAI,CAAC;QACD,SAAS,EAAE,CAAC;IAChB,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACtB,MAAM,CAAC,eAAe,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,EAAE;QACtC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB,EAAE,IAAI,EAAE,IAAI,SAAS;QAC3D,OAAO,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;KAC/D,CAAC,CAAC;IACH,MAAM,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agnox runs list | agnox runs failures <taskId>
|
|
3
|
+
*/
|
|
4
|
+
import { type ICommandContext } from './context.js';
|
|
5
|
+
export declare function runsList(args: string[], ctx: ICommandContext): Promise<number>;
|
|
6
|
+
export declare function runsFailures(args: string[], ctx: ICommandContext): Promise<number>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agnox runs list | agnox runs failures <taskId>
|
|
3
|
+
*/
|
|
4
|
+
import { parseArgs } from 'node:util';
|
|
5
|
+
import { firstLines, formatDuration, formatTime, sanitizeForTerminal as clean, table } from '../format.js';
|
|
6
|
+
import { parsePositiveInt, UsageError } from './context.js';
|
|
7
|
+
export async function runsList(args, ctx) {
|
|
8
|
+
const { values } = parseArgs({
|
|
9
|
+
args,
|
|
10
|
+
options: {
|
|
11
|
+
project: { type: 'string' },
|
|
12
|
+
status: { type: 'string' },
|
|
13
|
+
limit: { type: 'string' },
|
|
14
|
+
json: { type: 'boolean', default: false },
|
|
15
|
+
},
|
|
16
|
+
strict: true,
|
|
17
|
+
});
|
|
18
|
+
const page = await ctx.client.listExecutions({
|
|
19
|
+
projectId: values.project ?? ctx.defaultProjectId,
|
|
20
|
+
status: values.status,
|
|
21
|
+
limit: parsePositiveInt(values.limit, '--limit'),
|
|
22
|
+
});
|
|
23
|
+
if (values.json) {
|
|
24
|
+
ctx.stdout(JSON.stringify(page.items, null, 2));
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
if (page.items.length === 0) {
|
|
28
|
+
ctx.stdout('No runs found.');
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
const rows = page.items.map((run) => [
|
|
32
|
+
clean(run.taskId), clean(run.status), formatTime(run.startTime), formatDuration(run.durationMs), `${clean(String(run.passed))}/${clean(String(run.failed))}`,
|
|
33
|
+
]);
|
|
34
|
+
for (const line of table(['TASK ID', 'STATUS', 'STARTED', 'DURATION', 'PASSED/FAILED'], rows))
|
|
35
|
+
ctx.stdout(line);
|
|
36
|
+
if (page.hasMore)
|
|
37
|
+
ctx.stdout(`… ${page.total - page.items.length} more (use --limit)`);
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
export async function runsFailures(args, ctx) {
|
|
41
|
+
const { values, positionals } = parseArgs({
|
|
42
|
+
args,
|
|
43
|
+
options: { json: { type: 'boolean', default: false } },
|
|
44
|
+
allowPositionals: true,
|
|
45
|
+
strict: true,
|
|
46
|
+
});
|
|
47
|
+
const taskId = positionals[0];
|
|
48
|
+
if (!taskId)
|
|
49
|
+
throw new UsageError('Usage: agnox runs failures <taskId>');
|
|
50
|
+
const failures = await ctx.client.getExecutionFailures(taskId);
|
|
51
|
+
if (values.json) {
|
|
52
|
+
ctx.stdout(JSON.stringify(failures, null, 2));
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
if (failures.items.length === 0) {
|
|
56
|
+
ctx.stdout(`No failed tests in run ${clean(failures.taskId)}.`);
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
ctx.stdout(`${failures.items.length} failed test${failures.items.length === 1 ? '' : 's'} in run ${clean(failures.taskId)}`);
|
|
60
|
+
for (const failure of failures.items) {
|
|
61
|
+
ctx.stdout('');
|
|
62
|
+
ctx.stdout(`✗ ${clean(failure.name)}${failure.isQuarantined ? ' [quarantined]' : ''}`);
|
|
63
|
+
if (failure.file)
|
|
64
|
+
ctx.stdout(` file: ${clean(failure.file)}`);
|
|
65
|
+
if (failure.failureSignature)
|
|
66
|
+
ctx.stdout(` signature: ${clean(failure.failureSignature)}`);
|
|
67
|
+
if (failure.testKey)
|
|
68
|
+
ctx.stdout(` test key: ${clean(failure.testKey)}`);
|
|
69
|
+
for (const line of firstLines(clean(failure.error ?? ''), 3))
|
|
70
|
+
ctx.stdout(` │ ${line}`);
|
|
71
|
+
}
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=runs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runs.js","sourceRoot":"","sources":["../../src/commands/runs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agnox trigger --image <img> --command <cmd> --env <environment> [--wait]
|
|
3
|
+
*/
|
|
4
|
+
import { type ICommandContext } from './context.js';
|
|
5
|
+
export declare const POLL_INTERVAL_MS = 5000;
|
|
6
|
+
export declare const DEFAULT_TIMEOUT_SECONDS = 1800;
|
|
7
|
+
export declare function trigger(args: string[], ctx: ICommandContext): Promise<number>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agnox trigger --image <img> --command <cmd> --env <environment> [--wait]
|
|
3
|
+
*/
|
|
4
|
+
import { parseArgs } from 'node:util';
|
|
5
|
+
import { formatDuration, sanitizeForTerminal as clean } from '../format.js';
|
|
6
|
+
import { parsePositiveInt, requireProject, UsageError } from './context.js';
|
|
7
|
+
export const POLL_INTERVAL_MS = 5000;
|
|
8
|
+
export const DEFAULT_TIMEOUT_SECONDS = 1800;
|
|
9
|
+
const ENVIRONMENTS = ['development', 'staging', 'production'];
|
|
10
|
+
const ACTIVE_STATUSES = new Set(['PENDING', 'RUNNING']);
|
|
11
|
+
export async function trigger(args, ctx) {
|
|
12
|
+
const { values } = parseArgs({
|
|
13
|
+
args,
|
|
14
|
+
options: {
|
|
15
|
+
image: { type: 'string' },
|
|
16
|
+
command: { type: 'string' },
|
|
17
|
+
env: { type: 'string' },
|
|
18
|
+
project: { type: 'string' },
|
|
19
|
+
'base-url': { type: 'string' },
|
|
20
|
+
folder: { type: 'string' },
|
|
21
|
+
wait: { type: 'boolean', default: false },
|
|
22
|
+
timeout: { type: 'string' },
|
|
23
|
+
json: { type: 'boolean', default: false },
|
|
24
|
+
},
|
|
25
|
+
strict: true,
|
|
26
|
+
});
|
|
27
|
+
if (!values.image || !values.command || !values.env) {
|
|
28
|
+
throw new UsageError('Usage: agnox trigger --image <img> --command <cmd> --env <development|staging|production> [--wait]');
|
|
29
|
+
}
|
|
30
|
+
const environment = values.env;
|
|
31
|
+
if (!ENVIRONMENTS.includes(environment))
|
|
32
|
+
throw new UsageError('--env must be development, staging or production');
|
|
33
|
+
const timeoutSeconds = parsePositiveInt(values.timeout, '--timeout') ?? DEFAULT_TIMEOUT_SECONDS;
|
|
34
|
+
const body = {
|
|
35
|
+
projectId: requireProject(ctx, values.project),
|
|
36
|
+
image: values.image,
|
|
37
|
+
command: values.command,
|
|
38
|
+
folder: values.folder ?? 'all',
|
|
39
|
+
config: { environment, ...(values['base-url'] ? { baseUrl: values['base-url'] } : {}) },
|
|
40
|
+
ciContext: { source: 'webhook' },
|
|
41
|
+
};
|
|
42
|
+
const started = await ctx.client.triggerExecution(body);
|
|
43
|
+
if (!values.wait) {
|
|
44
|
+
ctx.stdout(values.json ? JSON.stringify(started, null, 2) : `Started run ${clean(started.taskId)}`);
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
if (!values.json)
|
|
48
|
+
ctx.stdout(`Started run ${clean(started.taskId)}; waiting for it to finish…`);
|
|
49
|
+
let waited = 0;
|
|
50
|
+
for (;;) {
|
|
51
|
+
await ctx.sleep(POLL_INTERVAL_MS);
|
|
52
|
+
waited += POLL_INTERVAL_MS;
|
|
53
|
+
const run = await ctx.client.getExecution(started.taskId);
|
|
54
|
+
if (!ACTIVE_STATUSES.has(run.status)) {
|
|
55
|
+
if (values.json)
|
|
56
|
+
ctx.stdout(JSON.stringify(run, null, 2));
|
|
57
|
+
else
|
|
58
|
+
ctx.stdout(`Run ${clean(run.taskId)} ${clean(run.status)} — ${clean(String(run.passed))} passed, ${clean(String(run.failed))} failed in ${formatDuration(run.durationMs)}`);
|
|
59
|
+
return run.status === 'PASSED' ? 0 : 2;
|
|
60
|
+
}
|
|
61
|
+
if (waited >= timeoutSeconds * 1000) {
|
|
62
|
+
ctx.stderr(`Timed out after ${timeoutSeconds} s waiting for run ${clean(run.taskId)} (still ${clean(run.status)})`);
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=trigger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trigger.js","sourceRoot":"","sources":["../../src/commands/trigger.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration from the environment:
|
|
3
|
+
* AGNOX_API_KEY required — an API key from Settings → My Profile
|
|
4
|
+
* AGNOX_API_URL optional — default https://api.agnox.dev
|
|
5
|
+
* AGNOX_PROJECT_ID optional — default project for commands and tools
|
|
6
|
+
*/
|
|
7
|
+
export declare const DEFAULT_API_URL = "https://api.agnox.dev";
|
|
8
|
+
export interface IAgnoxConfig {
|
|
9
|
+
apiUrl: string;
|
|
10
|
+
apiKey: string;
|
|
11
|
+
projectId?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class ConfigError extends Error {
|
|
14
|
+
constructor(message: string);
|
|
15
|
+
}
|
|
16
|
+
export declare function loadConfig(env: Record<string, string | undefined>): IAgnoxConfig;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration from the environment:
|
|
3
|
+
* AGNOX_API_KEY required — an API key from Settings → My Profile
|
|
4
|
+
* AGNOX_API_URL optional — default https://api.agnox.dev
|
|
5
|
+
* AGNOX_PROJECT_ID optional — default project for commands and tools
|
|
6
|
+
*/
|
|
7
|
+
export const DEFAULT_API_URL = 'https://api.agnox.dev';
|
|
8
|
+
/** Hosts where plain http is acceptable: the key never leaves the machine. WHATWG URL keeps the brackets on IPv6. */
|
|
9
|
+
const LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]']);
|
|
10
|
+
export class ConfigError extends Error {
|
|
11
|
+
constructor(message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = 'ConfigError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function loadConfig(env) {
|
|
17
|
+
const apiKey = env.AGNOX_API_KEY?.trim();
|
|
18
|
+
if (!apiKey) {
|
|
19
|
+
throw new ConfigError('AGNOX_API_KEY is not set. Create an API key in Agnox (Settings → My Profile → API keys) and export it as AGNOX_API_KEY.');
|
|
20
|
+
}
|
|
21
|
+
const rawUrl = env.AGNOX_API_URL?.trim() || DEFAULT_API_URL;
|
|
22
|
+
let url;
|
|
23
|
+
try {
|
|
24
|
+
url = new URL(rawUrl);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
throw new ConfigError(`AGNOX_API_URL is not a valid URL: ${rawUrl}`);
|
|
28
|
+
}
|
|
29
|
+
if (url.protocol !== 'https:' && url.protocol !== 'http:') {
|
|
30
|
+
throw new ConfigError('AGNOX_API_URL must be an http or https URL');
|
|
31
|
+
}
|
|
32
|
+
if (url.username || url.password || url.search || url.hash) {
|
|
33
|
+
throw new ConfigError('AGNOX_API_URL must not contain credentials, a query string or a fragment');
|
|
34
|
+
}
|
|
35
|
+
if (url.protocol === 'http:' && !LOOPBACK_HOSTS.has(url.hostname)) {
|
|
36
|
+
throw new ConfigError(`AGNOX_API_URL must use https for ${url.host}; plain http is allowed only for localhost, 127.0.0.1 and [::1]`);
|
|
37
|
+
}
|
|
38
|
+
const config = { apiUrl: rawUrl.replace(/\/+$/, ''), apiKey };
|
|
39
|
+
const projectId = env.AGNOX_PROJECT_ID?.trim();
|
|
40
|
+
if (projectId)
|
|
41
|
+
config.projectId = projectId;
|
|
42
|
+
return config;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,uBAAuB,CAAC;AAEvD,qHAAqH;AACrH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;AAQpE,MAAM,OAAO,WAAY,SAAQ,KAAK;IAClC,YAAY,OAAe;QACvB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC9B,CAAC;CACJ;AAED,MAAM,UAAU,UAAU,CAAC,GAAuC;IAC9D,MAAM,MAAM,GAAG,GAAG,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,MAAM,IAAI,WAAW,CAAC,yHAAyH,CAAC,CAAC;IACrJ,CAAC;IAED,MAAM,MAAM,GAAG,GAAG,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,eAAe,CAAC;IAC5D,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACD,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACL,MAAM,IAAI,WAAW,CAAC,qCAAqC,MAAM,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACxD,MAAM,IAAI,WAAW,CAAC,4CAA4C,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QACzD,MAAM,IAAI,WAAW,CAAC,0EAA0E,CAAC,CAAC;IACtG,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,WAAW,CAAC,oCAAoC,GAAG,CAAC,IAAI,iEAAiE,CAAC,CAAC;IACzI,CAAC;IAED,MAAM,MAAM,GAAiB,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5E,MAAM,SAAS,GAAG,GAAG,CAAC,gBAAgB,EAAE,IAAI,EAAE,CAAC;IAC/C,IAAI,SAAS;QAAE,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC;IAC5C,OAAO,MAAM,CAAC;AAClB,CAAC"}
|
package/dist/format.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plain-text formatting for the CLI.
|
|
3
|
+
*/
|
|
4
|
+
/** "1m 5s", "850ms", "2h 3m"; "—" when unknown. */
|
|
5
|
+
export declare function formatDuration(ms: number | null | undefined): string;
|
|
6
|
+
/** "2026-11-12 10:00" (UTC) from an ISO string; "—" when missing. */
|
|
7
|
+
export declare function formatTime(iso: string | null | undefined): string;
|
|
8
|
+
/** Left-aligned columns separated by two spaces. */
|
|
9
|
+
export declare function table(headers: string[], rows: string[][]): string[];
|
|
10
|
+
/** First `count` non-empty lines of a text. */
|
|
11
|
+
export declare function firstLines(text: string, count: number): string[];
|
|
12
|
+
export declare function sanitizeForTerminal(text: string): string;
|
package/dist/format.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plain-text formatting for the CLI.
|
|
3
|
+
*/
|
|
4
|
+
/** "1m 5s", "850ms", "2h 3m"; "—" when unknown. */
|
|
5
|
+
export function formatDuration(ms) {
|
|
6
|
+
if (ms === null || ms === undefined || !Number.isFinite(ms))
|
|
7
|
+
return '—';
|
|
8
|
+
if (ms < 1000)
|
|
9
|
+
return `${Math.round(ms)}ms`;
|
|
10
|
+
const totalSeconds = Math.round(ms / 1000);
|
|
11
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
12
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
13
|
+
const seconds = totalSeconds % 60;
|
|
14
|
+
if (hours > 0)
|
|
15
|
+
return `${hours}h ${minutes}m`;
|
|
16
|
+
if (minutes > 0)
|
|
17
|
+
return `${minutes}m ${seconds}s`;
|
|
18
|
+
return `${seconds}s`;
|
|
19
|
+
}
|
|
20
|
+
/** "2026-11-12 10:00" (UTC) from an ISO string; "—" when missing. */
|
|
21
|
+
export function formatTime(iso) {
|
|
22
|
+
if (!iso)
|
|
23
|
+
return '—';
|
|
24
|
+
const date = new Date(iso);
|
|
25
|
+
if (Number.isNaN(date.getTime()))
|
|
26
|
+
return '—';
|
|
27
|
+
return date.toISOString().slice(0, 16).replace('T', ' ');
|
|
28
|
+
}
|
|
29
|
+
/** Left-aligned columns separated by two spaces. */
|
|
30
|
+
export function table(headers, rows) {
|
|
31
|
+
const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? '').length)));
|
|
32
|
+
const line = (cells) => cells.map((cell, i) => (i === cells.length - 1 ? cell : cell.padEnd(widths[i]))).join(' ').trimEnd();
|
|
33
|
+
return [line(headers), ...rows.map(line)];
|
|
34
|
+
}
|
|
35
|
+
/** First `count` non-empty lines of a text. */
|
|
36
|
+
export function firstLines(text, count) {
|
|
37
|
+
return text.split(/\r?\n/).map((l) => l.trimEnd()).filter((l) => l.trim().length > 0).slice(0, count);
|
|
38
|
+
}
|
|
39
|
+
/** C0 controls except
|
|
40
|
+
and , DEL and C1 (U+0080-009F): they let server text drive the terminal. Built from code points to keep control characters out of the source. */
|
|
41
|
+
const UNSAFE_TERMINAL_CHARS = new RegExp(`[${String.fromCharCode(0)}-${String.fromCharCode(8)}${String.fromCharCode(0x0b)}-${String.fromCharCode(0x1f)}${String.fromCharCode(0x7f)}-${String.fromCharCode(0x9f)}]`, 'g');
|
|
42
|
+
export function sanitizeForTerminal(text) {
|
|
43
|
+
return text.replace(UNSAFE_TERMINAL_CHARS, '');
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency-free MCP server: JSON-RPC 2.0 over stdio.
|
|
3
|
+
*
|
|
4
|
+
* Framing (MCP stdio transport): one JSON message per line, UTF-8, no embedded
|
|
5
|
+
* newlines. Reading tolerates CRLF, blank lines and messages split across
|
|
6
|
+
* chunks. Only protocol messages are ever written to the output stream.
|
|
7
|
+
*
|
|
8
|
+
* Methods: initialize, ping, tools/list, tools/call; notifications get no
|
|
9
|
+
* answer; anything else is -32601. A failing tool is a normal result with
|
|
10
|
+
* isError: true and a readable message (never a stack trace or the key).
|
|
11
|
+
*/
|
|
12
|
+
import type { Readable, Writable } from 'node:stream';
|
|
13
|
+
import { type AgnoxClient } from '../client.js';
|
|
14
|
+
import { type IToolContext } from './tools.js';
|
|
15
|
+
/** Newest first; initialize echoes the client's version when it is listed here. */
|
|
16
|
+
export declare const SUPPORTED_PROTOCOL_VERSIONS: readonly ["2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05"];
|
|
17
|
+
export interface IMcpServerOptions extends IToolContext {
|
|
18
|
+
/** Strings to remove from any text sent back (the API key). */
|
|
19
|
+
secrets?: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface IMcpServer {
|
|
22
|
+
handle(message: unknown): Promise<unknown | null>;
|
|
23
|
+
}
|
|
24
|
+
/** `getClient` is called per tool call, so a configuration error becomes a tool error instead of a crash. */
|
|
25
|
+
export declare function createMcpServer(getClient: () => AgnoxClient, options?: IMcpServerOptions): IMcpServer;
|
|
26
|
+
/**
|
|
27
|
+
* Serve newline-delimited JSON-RPC on a pair of streams until the input ends.
|
|
28
|
+
* Messages are handled in order, one at a time.
|
|
29
|
+
*/
|
|
30
|
+
export declare function serveStdio(server: IMcpServer, input: Readable, output: Writable): Promise<void>;
|