@autifyhq/aximo-cli 0.1.0

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 (135) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +379 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +21 -0
  5. package/dist/client.d.ts +18 -0
  6. package/dist/client.js +90 -0
  7. package/dist/client.test.d.ts +1 -0
  8. package/dist/client.test.js +127 -0
  9. package/dist/commands/configure.d.ts +24 -0
  10. package/dist/commands/configure.js +103 -0
  11. package/dist/commands/configure.test.d.ts +1 -0
  12. package/dist/commands/configure.test.js +96 -0
  13. package/dist/commands/device/connect.d.ts +2 -0
  14. package/dist/commands/device/connect.js +84 -0
  15. package/dist/commands/device/doctor.d.ts +34 -0
  16. package/dist/commands/device/doctor.js +421 -0
  17. package/dist/commands/device/doctor.test.d.ts +1 -0
  18. package/dist/commands/device/doctor.test.js +89 -0
  19. package/dist/commands/device/index.d.ts +2 -0
  20. package/dist/commands/device/index.js +16 -0
  21. package/dist/commands/device/list.d.ts +20 -0
  22. package/dist/commands/device/list.js +40 -0
  23. package/dist/commands/device/list.test.d.ts +1 -0
  24. package/dist/commands/device/list.test.js +38 -0
  25. package/dist/commands/device/logs.d.ts +34 -0
  26. package/dist/commands/device/logs.js +160 -0
  27. package/dist/commands/device/logs.test.d.ts +1 -0
  28. package/dist/commands/device/logs.test.js +70 -0
  29. package/dist/commands/device/paths.d.ts +12 -0
  30. package/dist/commands/device/paths.js +40 -0
  31. package/dist/commands/device/ping.d.ts +21 -0
  32. package/dist/commands/device/ping.js +66 -0
  33. package/dist/commands/device/ping.test.d.ts +1 -0
  34. package/dist/commands/device/ping.test.js +68 -0
  35. package/dist/commands/device/register.d.ts +23 -0
  36. package/dist/commands/device/register.js +83 -0
  37. package/dist/commands/device/reset.d.ts +30 -0
  38. package/dist/commands/device/reset.js +67 -0
  39. package/dist/commands/device/reset.test.d.ts +1 -0
  40. package/dist/commands/device/reset.test.js +69 -0
  41. package/dist/commands/device/setup.d.ts +25 -0
  42. package/dist/commands/device/setup.js +105 -0
  43. package/dist/commands/device/setup.test.d.ts +1 -0
  44. package/dist/commands/device/setup.test.js +64 -0
  45. package/dist/commands/device/status.d.ts +16 -0
  46. package/dist/commands/device/status.js +20 -0
  47. package/dist/commands/device/unregister.d.ts +14 -0
  48. package/dist/commands/device/unregister.js +60 -0
  49. package/dist/commands/health/check.d.ts +5 -0
  50. package/dist/commands/health/check.js +20 -0
  51. package/dist/commands/health/check.test.d.ts +1 -0
  52. package/dist/commands/health/check.test.js +26 -0
  53. package/dist/commands/health/index.d.ts +2 -0
  54. package/dist/commands/health/index.js +7 -0
  55. package/dist/commands/project/index.d.ts +2 -0
  56. package/dist/commands/project/index.js +7 -0
  57. package/dist/commands/project/list.d.ts +7 -0
  58. package/dist/commands/project/list.js +20 -0
  59. package/dist/commands/project/list.test.d.ts +1 -0
  60. package/dist/commands/project/list.test.js +28 -0
  61. package/dist/commands/schema.d.ts +27 -0
  62. package/dist/commands/schema.js +146 -0
  63. package/dist/commands/schema.test.d.ts +1 -0
  64. package/dist/commands/schema.test.js +38 -0
  65. package/dist/commands/session/create.d.ts +78 -0
  66. package/dist/commands/session/create.js +89 -0
  67. package/dist/commands/session/get.d.ts +11 -0
  68. package/dist/commands/session/get.js +30 -0
  69. package/dist/commands/session/index.d.ts +2 -0
  70. package/dist/commands/session/index.js +8 -0
  71. package/dist/commands/session/session.test.d.ts +1 -0
  72. package/dist/commands/session/session.test.js +128 -0
  73. package/dist/commands/trigger/case/get.d.ts +14 -0
  74. package/dist/commands/trigger/case/get.js +33 -0
  75. package/dist/commands/trigger/case/index.d.ts +2 -0
  76. package/dist/commands/trigger/case/index.js +8 -0
  77. package/dist/commands/trigger/case/run.d.ts +58 -0
  78. package/dist/commands/trigger/case/run.js +81 -0
  79. package/dist/commands/trigger/index.d.ts +2 -0
  80. package/dist/commands/trigger/index.js +8 -0
  81. package/dist/commands/trigger/plan/get.d.ts +14 -0
  82. package/dist/commands/trigger/plan/get.js +33 -0
  83. package/dist/commands/trigger/plan/index.d.ts +2 -0
  84. package/dist/commands/trigger/plan/index.js +8 -0
  85. package/dist/commands/trigger/plan/run.d.ts +33 -0
  86. package/dist/commands/trigger/plan/run.js +63 -0
  87. package/dist/commands/trigger/trigger.test.d.ts +1 -0
  88. package/dist/commands/trigger/trigger.test.js +107 -0
  89. package/dist/commands/upload/create.d.ts +32 -0
  90. package/dist/commands/upload/create.js +65 -0
  91. package/dist/commands/upload/get.d.ts +10 -0
  92. package/dist/commands/upload/get.js +30 -0
  93. package/dist/commands/upload/index.d.ts +2 -0
  94. package/dist/commands/upload/index.js +11 -0
  95. package/dist/commands/upload/list.d.ts +15 -0
  96. package/dist/commands/upload/list.js +31 -0
  97. package/dist/commands/upload/put.d.ts +24 -0
  98. package/dist/commands/upload/put.js +62 -0
  99. package/dist/commands/upload/submit.d.ts +19 -0
  100. package/dist/commands/upload/submit.js +36 -0
  101. package/dist/commands/upload/upload.test.d.ts +1 -0
  102. package/dist/commands/upload/upload.test.js +133 -0
  103. package/dist/config.d.ts +7 -0
  104. package/dist/config.js +36 -0
  105. package/dist/desktop-server/agent-sync.d.ts +19 -0
  106. package/dist/desktop-server/agent-sync.js +141 -0
  107. package/dist/desktop-server/agent-sync.test.d.ts +1 -0
  108. package/dist/desktop-server/agent-sync.test.js +130 -0
  109. package/dist/desktop-server/setup.d.ts +19 -0
  110. package/dist/desktop-server/setup.js +200 -0
  111. package/dist/errors.d.ts +2 -0
  112. package/dist/errors.js +71 -0
  113. package/dist/errors.test.d.ts +1 -0
  114. package/dist/errors.test.js +88 -0
  115. package/dist/index.d.ts +19 -0
  116. package/dist/index.js +17 -0
  117. package/dist/mutate.d.ts +13 -0
  118. package/dist/mutate.js +25 -0
  119. package/dist/mutate.test.d.ts +1 -0
  120. package/dist/mutate.test.js +49 -0
  121. package/dist/output.d.ts +5 -0
  122. package/dist/output.js +23 -0
  123. package/dist/output.test.d.ts +1 -0
  124. package/dist/output.test.js +42 -0
  125. package/dist/test-setup.d.ts +1 -0
  126. package/dist/test-setup.js +13 -0
  127. package/dist/test-utils.d.ts +4 -0
  128. package/dist/test-utils.js +5 -0
  129. package/dist/types.d.ts +121 -0
  130. package/dist/types.js +2 -0
  131. package/dist/validate.d.ts +14 -0
  132. package/dist/validate.js +103 -0
  133. package/dist/validate.test.d.ts +1 -0
  134. package/dist/validate.test.js +96 -0
  135. package/package.json +72 -0
@@ -0,0 +1,146 @@
1
+ import { defineCommand } from "citty";
2
+ import { formatSuccess, formatError, printResult } from "../output.js";
3
+ import pkg from "../../package.json" with { type: "json" };
4
+ function arg(name, type, description, required = false) {
5
+ return { name, type, description, required };
6
+ }
7
+ const MUTATE_ARGS = [
8
+ arg("json", "string", "Raw JSON request body (replaces individual flags)"),
9
+ arg("dry-run", "boolean", "Validate and show request without calling API"),
10
+ ];
11
+ function cmd(name, description, args = [], subCommands) {
12
+ const schema = { name, description, args };
13
+ if (subCommands && subCommands.length > 0)
14
+ schema.subCommands = subCommands;
15
+ return schema;
16
+ }
17
+ export function getSchema() {
18
+ return {
19
+ name: "aximo",
20
+ version: pkg.version,
21
+ commands: [
22
+ cmd("health", "Health commands", [], [cmd("check", "GET /api/health")]),
23
+ cmd("session", "Session commands", [], [
24
+ cmd("create", "POST /api/sessions", [
25
+ arg("title", "string", "Session title"),
26
+ arg("prompt", "string", "Session prompt"),
27
+ arg("project-id", "string", "Project ID"),
28
+ arg("platform", "string", "ANDROID | IOS"),
29
+ arg("model", "string", ""),
30
+ arg("start-url", "string", ""),
31
+ arg("case-id", "string", ""),
32
+ arg("tags", "string", "comma-separated"),
33
+ arg("device-arn", "string", ""),
34
+ arg("device-name", "string", ""),
35
+ arg("upload-arn", "string", ""),
36
+ arg("upload-type", "string", "ANDROID_APP | IOS_APP"),
37
+ arg("app-name", "string", ""),
38
+ arg("bundle-id", "string", ""),
39
+ ...MUTATE_ARGS,
40
+ ]),
41
+ cmd("get", "GET /api/sessions/{sessionId}", [
42
+ arg("sessionId", "positional", "Session ID", true),
43
+ ]),
44
+ ]),
45
+ cmd("trigger", "Trigger commands", [], [
46
+ cmd("case", "Case trigger commands", [], [
47
+ cmd("run", "POST /api/triggers/cases/{caseId}/run", [
48
+ arg("caseId", "positional", "Case ID", true),
49
+ arg("model", "string", ""),
50
+ arg("hostname-override-ids", "string", "comma-separated"),
51
+ arg("device-arn", "string", ""),
52
+ arg("device-name", "string", ""),
53
+ arg("platform", "string", ""),
54
+ arg("upload-arn", "string", ""),
55
+ arg("upload-type", "string", ""),
56
+ arg("app-name", "string", ""),
57
+ ...MUTATE_ARGS,
58
+ ]),
59
+ cmd("get", "GET /api/triggers/cases/{caseId}/sessions/{sessionId}", [
60
+ arg("caseId", "positional", "Case ID", true),
61
+ arg("sessionId", "positional", "Session ID", true),
62
+ ]),
63
+ ]),
64
+ cmd("plan", "Plan trigger commands", [], [
65
+ cmd("run", "POST /api/triggers/plans/{planId}/run", [
66
+ arg("planId", "positional", "Plan ID", true),
67
+ arg("model", "string", ""),
68
+ arg("mobile-config", "string", "JSON object string"),
69
+ ...MUTATE_ARGS,
70
+ ]),
71
+ cmd("get", "GET /api/triggers/plans/{planId}/runs/{planRunId}", [
72
+ arg("planId", "positional", "Plan ID", true),
73
+ arg("planRunId", "positional", "Plan Run ID", true),
74
+ ]),
75
+ ]),
76
+ ]),
77
+ cmd("device", "Device commands", [], [
78
+ cmd("list", "GET /api/devices", [
79
+ arg("platform", "string", "ANDROID | IOS"),
80
+ arg("available-only", "boolean", ""),
81
+ ]),
82
+ ]),
83
+ cmd("upload", "Upload commands", [], [
84
+ cmd("create", "POST /api/uploads", [
85
+ arg("file-name", "string", "File name"),
86
+ arg("file-size", "string", "File size in bytes"),
87
+ arg("platform", "string", "ANDROID | IOS"),
88
+ ...MUTATE_ARGS,
89
+ ]),
90
+ cmd("list", "GET /api/uploads", [arg("file-type", "string", "ANDROID_APP | IOS_APP")]),
91
+ cmd("get", "GET /api/uploads/{uploadId}", [
92
+ arg("uploadId", "positional", "Upload ID", true),
93
+ ]),
94
+ cmd("put", "PUT /api/uploads/{uploadId} (octet-stream)", [
95
+ arg("uploadId", "positional", "Upload ID", true),
96
+ arg("file", "string", "Local path to the file"),
97
+ arg("dry-run", "boolean", "Validate and show request without calling API"),
98
+ ]),
99
+ cmd("submit", "POST /api/uploads/{uploadId}/submit", [
100
+ arg("uploadId", "positional", "Upload ID", true),
101
+ arg("dry-run", "boolean", "Validate and show request without calling API"),
102
+ ]),
103
+ ]),
104
+ cmd("project", "Project commands", [], [cmd("list", "GET /api/organizations/projects")]),
105
+ cmd("schema", "Show CLI schema for agent introspection", [
106
+ arg("command", "positional", "Command path (e.g. session.create)"),
107
+ ]),
108
+ ],
109
+ };
110
+ }
111
+ export function lookupCommand(path) {
112
+ const parts = path.split(".");
113
+ let commands = getSchema().commands;
114
+ let found;
115
+ for (const part of parts) {
116
+ found = commands.find((c) => c.name === part);
117
+ if (!found)
118
+ return undefined;
119
+ commands = found.subCommands ?? [];
120
+ }
121
+ return found;
122
+ }
123
+ export default defineCommand({
124
+ meta: { name: "schema", description: "Show CLI schema for agent introspection" },
125
+ args: {
126
+ command: {
127
+ type: "positional",
128
+ description: "Command path (e.g. session.create)",
129
+ required: false,
130
+ },
131
+ },
132
+ run({ args }) {
133
+ if (args.command) {
134
+ const found = lookupCommand(args.command);
135
+ if (found) {
136
+ printResult(formatSuccess(found));
137
+ }
138
+ else {
139
+ printResult(formatError("not_found", `Command '${args.command}' not found`, false));
140
+ }
141
+ }
142
+ else {
143
+ printResult(formatSuccess({ commands: getSchema().commands }));
144
+ }
145
+ },
146
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,38 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { getSchema, lookupCommand } from "./schema.js";
3
+ describe("getSchema", () => {
4
+ it("returns aximo with commands", () => {
5
+ const s = getSchema();
6
+ expect(s.name).toBe("aximo");
7
+ expect(s.commands.length).toBeGreaterThan(0);
8
+ expect(s.commands.find((c) => c.name === "schema")).toBeDefined();
9
+ });
10
+ it("advertises --json and --dry-run on mutating commands", () => {
11
+ const sessionCreate = lookupCommand("session.create");
12
+ expect(sessionCreate).toBeDefined();
13
+ const argNames = sessionCreate?.args.map((a) => a.name) ?? [];
14
+ expect(argNames).toContain("json");
15
+ expect(argNames).toContain("dry-run");
16
+ for (const path of ["trigger.case.run", "trigger.plan.run", "upload.create"]) {
17
+ const c = lookupCommand(path);
18
+ const names = c?.args.map((a) => a.name) ?? [];
19
+ expect(names, path).toContain("json");
20
+ expect(names, path).toContain("dry-run");
21
+ }
22
+ for (const path of ["upload.put", "upload.submit"]) {
23
+ const c = lookupCommand(path);
24
+ const names = c?.args.map((a) => a.name) ?? [];
25
+ expect(names, path).toContain("dry-run");
26
+ }
27
+ });
28
+ });
29
+ describe("lookupCommand", () => {
30
+ it("resolves dotted paths", () => {
31
+ expect(lookupCommand("session.create")?.name).toBe("create");
32
+ expect(lookupCommand("trigger.case.run")?.name).toBe("run");
33
+ });
34
+ it("returns undefined for unknown", () => {
35
+ expect(lookupCommand("nope")).toBeUndefined();
36
+ expect(lookupCommand("session.nope")).toBeUndefined();
37
+ });
38
+ });
@@ -0,0 +1,78 @@
1
+ import type { Envelope, CreateSessionResult } from "../../types.js";
2
+ import { type ClientDeps } from "../../client.js";
3
+ import { type DryRunResult } from "../../mutate.js";
4
+ export interface CreateSessionOptions {
5
+ title?: unknown;
6
+ prompt?: unknown;
7
+ projectId?: unknown;
8
+ platform?: unknown;
9
+ model?: unknown;
10
+ startUrl?: unknown;
11
+ caseId?: unknown;
12
+ tags?: unknown;
13
+ deviceArn?: unknown;
14
+ deviceName?: unknown;
15
+ uploadArn?: unknown;
16
+ uploadType?: unknown;
17
+ appName?: unknown;
18
+ bundleId?: unknown;
19
+ json?: unknown;
20
+ dryRun?: unknown;
21
+ }
22
+ export declare function runSessionCreate(options: CreateSessionOptions, deps?: ClientDeps): Promise<Envelope<CreateSessionResult | DryRunResult>>;
23
+ declare const _default: import("citty").CommandDef<{
24
+ readonly title: {
25
+ readonly type: "string";
26
+ };
27
+ readonly prompt: {
28
+ readonly type: "string";
29
+ };
30
+ readonly "project-id": {
31
+ readonly type: "string";
32
+ };
33
+ readonly platform: {
34
+ readonly type: "string";
35
+ readonly description: "ANDROID | IOS";
36
+ };
37
+ readonly model: {
38
+ readonly type: "string";
39
+ };
40
+ readonly "start-url": {
41
+ readonly type: "string";
42
+ };
43
+ readonly "case-id": {
44
+ readonly type: "string";
45
+ };
46
+ readonly tags: {
47
+ readonly type: "string";
48
+ readonly description: "comma-separated";
49
+ };
50
+ readonly "device-arn": {
51
+ readonly type: "string";
52
+ };
53
+ readonly "device-name": {
54
+ readonly type: "string";
55
+ };
56
+ readonly "upload-arn": {
57
+ readonly type: "string";
58
+ };
59
+ readonly "upload-type": {
60
+ readonly type: "string";
61
+ readonly description: "ANDROID_APP | IOS_APP";
62
+ };
63
+ readonly "app-name": {
64
+ readonly type: "string";
65
+ };
66
+ readonly "bundle-id": {
67
+ readonly type: "string";
68
+ };
69
+ readonly json: {
70
+ readonly type: "string";
71
+ readonly description: "Raw JSON request body (replaces individual flags)";
72
+ };
73
+ readonly "dry-run": {
74
+ readonly type: "boolean";
75
+ readonly description: "Validate and show request without calling API";
76
+ };
77
+ }>;
78
+ export default _default;
@@ -0,0 +1,89 @@
1
+ import { defineCommand } from "citty";
2
+ import { formatSuccess, printResult, validationError } from "../../output.js";
3
+ import { handleApiError } from "../../errors.js";
4
+ import { request } from "../../client.js";
5
+ import { requireString, optionalString, parsePlatform, parseFileType, parseTags, } from "../../validate.js";
6
+ import { dryRunEnvelope, resolveJsonOverride } from "../../mutate.js";
7
+ export async function runSessionCreate(options, deps) {
8
+ let body;
9
+ const override = resolveJsonOverride(options.json);
10
+ if (override && "error" in override)
11
+ return override.error;
12
+ if (override) {
13
+ body = override.body;
14
+ }
15
+ else {
16
+ try {
17
+ body = {
18
+ title: requireString("title", options.title),
19
+ prompt: requireString("prompt", options.prompt),
20
+ projectId: requireString("projectId", options.projectId),
21
+ platform: parsePlatform(options.platform),
22
+ model: optionalString("model", options.model),
23
+ startUrl: optionalString("startUrl", options.startUrl),
24
+ caseId: optionalString("caseId", options.caseId),
25
+ tags: parseTags(options.tags),
26
+ deviceArn: optionalString("deviceArn", options.deviceArn),
27
+ deviceName: optionalString("deviceName", options.deviceName),
28
+ uploadArn: optionalString("uploadArn", options.uploadArn),
29
+ uploadType: parseFileType(options.uploadType),
30
+ appName: optionalString("appName", options.appName),
31
+ bundleId: optionalString("bundleId", options.bundleId),
32
+ };
33
+ }
34
+ catch (err) {
35
+ return validationError(err);
36
+ }
37
+ }
38
+ if (options.dryRun) {
39
+ return dryRunEnvelope("POST", "/api/sessions", body);
40
+ }
41
+ try {
42
+ const res = await request("/api/sessions", { method: "POST", body }, deps ?? {});
43
+ return formatSuccess(res);
44
+ }
45
+ catch (err) {
46
+ return handleApiError(err);
47
+ }
48
+ }
49
+ export default defineCommand({
50
+ meta: { name: "create", description: "Create an Aximo session" },
51
+ args: {
52
+ title: { type: "string" },
53
+ prompt: { type: "string" },
54
+ "project-id": { type: "string" },
55
+ platform: { type: "string", description: "ANDROID | IOS" },
56
+ model: { type: "string" },
57
+ "start-url": { type: "string" },
58
+ "case-id": { type: "string" },
59
+ tags: { type: "string", description: "comma-separated" },
60
+ "device-arn": { type: "string" },
61
+ "device-name": { type: "string" },
62
+ "upload-arn": { type: "string" },
63
+ "upload-type": { type: "string", description: "ANDROID_APP | IOS_APP" },
64
+ "app-name": { type: "string" },
65
+ "bundle-id": { type: "string" },
66
+ json: { type: "string", description: "Raw JSON request body (replaces individual flags)" },
67
+ "dry-run": { type: "boolean", description: "Validate and show request without calling API" },
68
+ },
69
+ async run({ args }) {
70
+ printResult(await runSessionCreate({
71
+ title: args.title,
72
+ prompt: args.prompt,
73
+ projectId: args["project-id"],
74
+ platform: args.platform,
75
+ model: args.model,
76
+ startUrl: args["start-url"],
77
+ caseId: args["case-id"],
78
+ tags: args.tags,
79
+ deviceArn: args["device-arn"],
80
+ deviceName: args["device-name"],
81
+ uploadArn: args["upload-arn"],
82
+ uploadType: args["upload-type"],
83
+ appName: args["app-name"],
84
+ bundleId: args["bundle-id"],
85
+ json: args.json,
86
+ dryRun: args["dry-run"],
87
+ }));
88
+ },
89
+ });
@@ -0,0 +1,11 @@
1
+ import type { Envelope, Session } from "../../types.js";
2
+ import { type ClientDeps } from "../../client.js";
3
+ export declare function runSessionGet(sessionIdInput: unknown, deps?: ClientDeps): Promise<Envelope<Session>>;
4
+ declare const _default: import("citty").CommandDef<{
5
+ readonly sessionId: {
6
+ readonly type: "positional";
7
+ readonly description: "Session ID";
8
+ readonly required: true;
9
+ };
10
+ }>;
11
+ export default _default;
@@ -0,0 +1,30 @@
1
+ import { defineCommand } from "citty";
2
+ import { formatSuccess, printResult, validationError } from "../../output.js";
3
+ import { handleApiError } from "../../errors.js";
4
+ import { request } from "../../client.js";
5
+ import { requireId } from "../../validate.js";
6
+ export async function runSessionGet(sessionIdInput, deps) {
7
+ let sessionId;
8
+ try {
9
+ sessionId = requireId("sessionId", sessionIdInput);
10
+ }
11
+ catch (err) {
12
+ return validationError(err);
13
+ }
14
+ try {
15
+ const res = await request(`/api/sessions/${encodeURIComponent(sessionId)}`, {}, deps ?? {});
16
+ return formatSuccess(res);
17
+ }
18
+ catch (err) {
19
+ return handleApiError(err);
20
+ }
21
+ }
22
+ export default defineCommand({
23
+ meta: { name: "get", description: "Get a session by id" },
24
+ args: {
25
+ sessionId: { type: "positional", description: "Session ID", required: true },
26
+ },
27
+ async run({ args }) {
28
+ printResult(await runSessionGet(args.sessionId));
29
+ },
30
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("citty").CommandDef<import("citty").ArgsDef>;
2
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import { defineCommand } from "citty";
2
+ export default defineCommand({
3
+ meta: { name: "session", description: "Session commands" },
4
+ subCommands: {
5
+ create: () => import("./create.js").then((m) => m.default),
6
+ get: () => import("./get.js").then((m) => m.default),
7
+ },
8
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,128 @@
1
+ import { afterAll, afterEach, beforeAll, describe, expect, it } from "vitest";
2
+ import { server, http, HttpResponse, TEST_BASE_URL } from "../../test-utils.js";
3
+ import { runSessionCreate } from "./create.js";
4
+ import { runSessionGet } from "./get.js";
5
+ beforeAll(() => {
6
+ process.env["AXIMO_API_KEY"] = "test-key";
7
+ process.env["AXIMO_BASE_URL"] = TEST_BASE_URL;
8
+ server.listen();
9
+ });
10
+ afterEach(() => server.resetHandlers());
11
+ afterAll(() => server.close());
12
+ const MIN = {
13
+ title: "t",
14
+ prompt: "p",
15
+ projectId: "proj-1",
16
+ };
17
+ describe("runSessionCreate", () => {
18
+ it("POSTs body and returns success envelope", async () => {
19
+ let seen;
20
+ server.use(http.post(`${TEST_BASE_URL}/api/sessions`, async ({ request: req }) => {
21
+ seen = await req.json();
22
+ return HttpResponse.json({ success: true, sessionId: "s1" }, { status: 201 });
23
+ }));
24
+ const result = await runSessionCreate({ ...MIN, platform: "IOS", tags: "a,b" });
25
+ expect(result.ok).toBe(true);
26
+ if (result.ok && !("dryRun" in result.data))
27
+ expect(result.data.sessionId).toBe("s1");
28
+ expect(seen).toMatchObject({
29
+ title: "t",
30
+ prompt: "p",
31
+ projectId: "proj-1",
32
+ platform: "IOS",
33
+ tags: ["a", "b"],
34
+ });
35
+ });
36
+ it("rejects missing title", async () => {
37
+ const result = await runSessionCreate({ prompt: "p", projectId: "x" });
38
+ expect(result.ok).toBe(false);
39
+ if (!result.ok)
40
+ expect(result.error.code).toBe("validation_error");
41
+ });
42
+ it("rejects invalid platform", async () => {
43
+ const result = await runSessionCreate({ ...MIN, platform: "BAD" });
44
+ expect(result.ok).toBe(false);
45
+ if (!result.ok)
46
+ expect(result.error.code).toBe("validation_error");
47
+ });
48
+ it("--json replaces individual flags and POSTs raw body", async () => {
49
+ let seen;
50
+ server.use(http.post(`${TEST_BASE_URL}/api/sessions`, async ({ request: req }) => {
51
+ seen = await req.json();
52
+ return HttpResponse.json({ success: true, sessionId: "s2" }, { status: 201 });
53
+ }));
54
+ const raw = JSON.stringify({ title: "raw", prompt: "rp", projectId: "p1", extra: true });
55
+ const result = await runSessionCreate({ json: raw });
56
+ expect(result.ok).toBe(true);
57
+ expect(seen).toEqual({ title: "raw", prompt: "rp", projectId: "p1", extra: true });
58
+ });
59
+ it("--json invalid returns validation_error with openapi hint", async () => {
60
+ const result = await runSessionCreate({ json: "{bad" });
61
+ expect(result.ok).toBe(false);
62
+ if (!result.ok) {
63
+ expect(result.error.code).toBe("validation_error");
64
+ expect(result.error.hint).toContain("openapi.yaml");
65
+ }
66
+ });
67
+ it("--dry-run returns request without calling API", async () => {
68
+ const result = await runSessionCreate({ ...MIN, dryRun: true });
69
+ expect(result.ok).toBe(true);
70
+ if (result.ok && "dryRun" in result.data) {
71
+ expect(result.data.dryRun).toBe(true);
72
+ expect(result.data.method).toBe("POST");
73
+ expect(result.data.url).toBe(`${TEST_BASE_URL}/api/sessions`);
74
+ }
75
+ });
76
+ it("returns envelope (not throw) when AXIMO_API_KEY unset", async () => {
77
+ const prev = process.env["AXIMO_API_KEY"];
78
+ delete process.env["AXIMO_API_KEY"];
79
+ try {
80
+ const result = await runSessionCreate(MIN);
81
+ expect(result.ok).toBe(false);
82
+ if (!result.ok) {
83
+ expect(result.error.code).toBe("unauthorized");
84
+ expect(result.error.message).toContain("AXIMO_API_KEY");
85
+ expect(result.error.hint).toContain("AXIMO_API_KEY");
86
+ }
87
+ }
88
+ finally {
89
+ if (prev !== undefined)
90
+ process.env["AXIMO_API_KEY"] = prev;
91
+ }
92
+ });
93
+ it("maps 401 to unauthorized", async () => {
94
+ server.use(http.post(`${TEST_BASE_URL}/api/sessions`, () => HttpResponse.json({ error: "Unauthorized" }, { status: 401 })));
95
+ const result = await runSessionCreate(MIN);
96
+ expect(result.ok).toBe(false);
97
+ if (!result.ok)
98
+ expect(result.error.code).toBe("unauthorized");
99
+ });
100
+ });
101
+ describe("runSessionGet", () => {
102
+ it("fetches session by id", async () => {
103
+ server.use(http.get(`${TEST_BASE_URL}/api/sessions/s1`, () => HttpResponse.json({ id: "s1", status: "running" })));
104
+ const result = await runSessionGet("s1");
105
+ expect(result.ok).toBe(true);
106
+ if (result.ok)
107
+ expect(result.data.id).toBe("s1");
108
+ });
109
+ it("rejects empty id", async () => {
110
+ const result = await runSessionGet("");
111
+ expect(result.ok).toBe(false);
112
+ if (!result.ok)
113
+ expect(result.error.code).toBe("validation_error");
114
+ });
115
+ it("rejects injected query chars in id (requireId)", async () => {
116
+ const result = await runSessionGet("s1?fields=name");
117
+ expect(result.ok).toBe(false);
118
+ if (!result.ok)
119
+ expect(result.error.code).toBe("validation_error");
120
+ });
121
+ it("maps 404", async () => {
122
+ server.use(http.get(`${TEST_BASE_URL}/api/sessions/missing`, () => HttpResponse.json({ error: "Not found" }, { status: 404 })));
123
+ const result = await runSessionGet("missing");
124
+ expect(result.ok).toBe(false);
125
+ if (!result.ok)
126
+ expect(result.error.code).toBe("not_found");
127
+ });
128
+ });
@@ -0,0 +1,14 @@
1
+ import type { Envelope, CaseRunStatus } from "../../../types.js";
2
+ import { type ClientDeps } from "../../../client.js";
3
+ export declare function runTriggerCaseGet(caseIdInput: unknown, sessionIdInput: unknown, deps?: ClientDeps): Promise<Envelope<CaseRunStatus>>;
4
+ declare const _default: import("citty").CommandDef<{
5
+ readonly caseId: {
6
+ readonly type: "positional";
7
+ readonly required: true;
8
+ };
9
+ readonly sessionId: {
10
+ readonly type: "positional";
11
+ readonly required: true;
12
+ };
13
+ }>;
14
+ export default _default;
@@ -0,0 +1,33 @@
1
+ import { defineCommand } from "citty";
2
+ import { formatSuccess, printResult, validationError } from "../../../output.js";
3
+ import { handleApiError } from "../../../errors.js";
4
+ import { request } from "../../../client.js";
5
+ import { requireId } from "../../../validate.js";
6
+ export async function runTriggerCaseGet(caseIdInput, sessionIdInput, deps) {
7
+ let caseId;
8
+ let sessionId;
9
+ try {
10
+ caseId = requireId("caseId", caseIdInput);
11
+ sessionId = requireId("sessionId", sessionIdInput);
12
+ }
13
+ catch (err) {
14
+ return validationError(err);
15
+ }
16
+ try {
17
+ const res = await request(`/api/triggers/cases/${encodeURIComponent(caseId)}/sessions/${encodeURIComponent(sessionId)}`, {}, deps ?? {});
18
+ return formatSuccess(res);
19
+ }
20
+ catch (err) {
21
+ return handleApiError(err);
22
+ }
23
+ }
24
+ export default defineCommand({
25
+ meta: { name: "get", description: "Get status of a case run session" },
26
+ args: {
27
+ caseId: { type: "positional", required: true },
28
+ sessionId: { type: "positional", required: true },
29
+ },
30
+ async run({ args }) {
31
+ printResult(await runTriggerCaseGet(args.caseId, args.sessionId));
32
+ },
33
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("citty").CommandDef<import("citty").ArgsDef>;
2
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import { defineCommand } from "citty";
2
+ export default defineCommand({
3
+ meta: { name: "case", description: "Case trigger commands" },
4
+ subCommands: {
5
+ run: () => import("./run.js").then((m) => m.default),
6
+ get: () => import("./get.js").then((m) => m.default),
7
+ },
8
+ });
@@ -0,0 +1,58 @@
1
+ import type { Envelope, CaseRunResult } from "../../../types.js";
2
+ import { type ClientDeps } from "../../../client.js";
3
+ import { type DryRunResult } from "../../../mutate.js";
4
+ export interface TriggerCaseRunOptions {
5
+ caseId?: unknown;
6
+ model?: unknown;
7
+ hostnameOverrideIds?: unknown;
8
+ deviceArn?: unknown;
9
+ deviceName?: unknown;
10
+ platform?: unknown;
11
+ uploadArn?: unknown;
12
+ uploadType?: unknown;
13
+ appName?: unknown;
14
+ json?: unknown;
15
+ dryRun?: unknown;
16
+ }
17
+ export declare function runTriggerCaseRun(options: TriggerCaseRunOptions, deps?: ClientDeps): Promise<Envelope<CaseRunResult | DryRunResult>>;
18
+ declare const _default: import("citty").CommandDef<{
19
+ readonly caseId: {
20
+ readonly type: "positional";
21
+ readonly description: "Case ID";
22
+ readonly required: true;
23
+ };
24
+ readonly model: {
25
+ readonly type: "string";
26
+ };
27
+ readonly "hostname-override-ids": {
28
+ readonly type: "string";
29
+ readonly description: "comma-separated";
30
+ };
31
+ readonly "device-arn": {
32
+ readonly type: "string";
33
+ };
34
+ readonly "device-name": {
35
+ readonly type: "string";
36
+ };
37
+ readonly platform: {
38
+ readonly type: "string";
39
+ };
40
+ readonly "upload-arn": {
41
+ readonly type: "string";
42
+ };
43
+ readonly "upload-type": {
44
+ readonly type: "string";
45
+ };
46
+ readonly "app-name": {
47
+ readonly type: "string";
48
+ };
49
+ readonly json: {
50
+ readonly type: "string";
51
+ readonly description: "Raw JSON request body";
52
+ };
53
+ readonly "dry-run": {
54
+ readonly type: "boolean";
55
+ readonly description: "Validate and show request without calling API";
56
+ };
57
+ }>;
58
+ export default _default;