@nodeint/migent 0.1.4 → 0.1.6

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 (48) hide show
  1. package/README.md +194 -138
  2. package/dist/commands/agent.d.ts +8 -1
  3. package/dist/commands/agent.js +381 -56
  4. package/dist/commands/config.js +23 -9
  5. package/dist/commands/execute.d.ts +6 -1
  6. package/dist/commands/execute.js +105 -20
  7. package/dist/commands/init.d.ts +1 -0
  8. package/dist/commands/init.js +70 -63
  9. package/dist/commands/prepare.d.ts +1 -0
  10. package/dist/commands/prepare.js +14 -0
  11. package/dist/commands/repair.d.ts +1 -0
  12. package/dist/commands/repair.js +22 -0
  13. package/dist/commands/service.js +5 -4
  14. package/dist/commands/sessions.d.ts +24 -1
  15. package/dist/commands/sessions.js +165 -13
  16. package/dist/commands/skill.js +58 -32
  17. package/dist/commands/watch.d.ts +2 -1
  18. package/dist/commands/watch.js +130 -67
  19. package/dist/commands/workspace-registry.js +10 -1
  20. package/dist/display.d.ts +1 -0
  21. package/dist/display.js +24 -9
  22. package/dist/errors.d.ts +3 -0
  23. package/dist/errors.js +6 -0
  24. package/dist/exits.d.ts +12 -0
  25. package/dist/exits.js +33 -0
  26. package/dist/follow-log.d.ts +29 -0
  27. package/dist/follow-log.js +172 -0
  28. package/dist/fs-utils.d.ts +3 -0
  29. package/dist/fs-utils.js +26 -0
  30. package/dist/index.js +5 -1
  31. package/dist/migrate.js +2 -17
  32. package/dist/program.js +429 -177
  33. package/dist/session-row.d.ts +20 -0
  34. package/dist/session-row.js +21 -0
  35. package/dist/signals.d.ts +3 -0
  36. package/dist/signals.js +56 -0
  37. package/dist/templates/migent/SKILL.md +163 -56
  38. package/dist/templates/migent/references/config.md +52 -0
  39. package/dist/templates/migent/references/inspect.md +32 -0
  40. package/dist/templates/migent/references/schema-config.yaml +35 -0
  41. package/dist/templates/migent/references/schema-workflow.yaml +71 -0
  42. package/dist/templates/migent/references/sessions.md +65 -0
  43. package/dist/text.d.ts +4 -0
  44. package/dist/text.js +13 -0
  45. package/dist/version.d.ts +1 -0
  46. package/dist/version.js +3 -0
  47. package/dist/workspace.js +5 -12
  48. package/package.json +4 -4
@@ -1,39 +1,124 @@
1
- import { AgentToolRunner, DEFAULT_MAX_DISPATCHES, executeNamedWorkflow, } from "@nodeint/migent-kernel";
1
+ import { readdirSync, readFileSync, realpathSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { AgentToolRunner, DEFAULT_MAX_DISPATCHES, executeNamedWorkflow, formatDuration, log, } from "@nodeint/migent-kernel";
4
+ import { printResumeCommand } from "../display.js";
2
5
  import { cliHooks } from "../hooks.js";
3
6
  import { requireCurrentSchema } from "../migrate.js";
4
7
  import { adapterMap } from "../provider.js";
8
+ import { text } from "../text.js";
5
9
  export async function executeWorkflow(workspace, options) {
6
10
  requireCurrentSchema(workspace);
7
11
  const once = options.action === "stage";
8
- const creating = options.action === "start" || (once && text(options.sessionId) === null);
9
- const maxAttempts = options.maxAttempts === undefined ? 3 : options.maxAttempts;
12
+ const startPrepared = options.startPrepared === true;
13
+ const sessionId = text(options.sessionId);
14
+ const creating = !startPrepared && (options.action === "start" || (once && sessionId === null));
10
15
  const maxDispatches = options.maxDispatches === undefined ? DEFAULT_MAX_DISPATCHES : options.maxDispatches;
11
16
  const runner = options.runner ?? cliHooks.runner ?? new AgentToolRunner(adapterMap());
17
+ runner.itemProgress = options.itemProgress === true;
12
18
  const result = await executeNamedWorkflow(workspace, {
13
- workflowId: creating ? (options.workflowId ?? null) : null,
19
+ workflowId: creating || startPrepared ? (options.workflowId ?? null) : null,
14
20
  task: creating ? (options.task ?? null) : null,
15
- sessionId: creating ? null : (options.sessionId ?? null),
21
+ sessionId: creating ? null : sessionId,
16
22
  priorSessionId: options.priorSessionId ?? null,
17
- maxAttempts: once ? null : maxAttempts,
23
+ startPrepared,
18
24
  maxDispatches: once ? null : maxDispatches,
25
+ continueFailed: options.continueFailed === true,
26
+ stageId: options.stageId ?? null,
19
27
  once,
20
28
  resetRevisions: options.action === "continue",
29
+ refreshWorkflow: options.refreshWorkflow === true,
30
+ reply: options.reply ?? null,
21
31
  }, runner);
22
- printResult(result);
32
+ printResult(workspace, result);
33
+ printResumeHint(result);
23
34
  return result.code;
24
35
  }
25
- function printResult(result) {
26
- process.stdout.write(`${JSON.stringify({
27
- session_id: result.sessionId,
28
- session_status: result.status,
29
- stop_reason: result.stopReason,
30
- outputs: result.outputs,
31
- stages: result.stages,
32
- })}\n`);
33
- }
34
- function text(value) {
35
- if (typeof value !== "string")
36
+ function printResumeHint(result) {
37
+ if (result.sessionId === "" || result.status === "completed" || result.stopReason === "completed")
38
+ return;
39
+ if (result.stopReason === "configuration")
40
+ return;
41
+ printResumeCommand(result.sessionId);
42
+ }
43
+ const INSPECT_EXIT_CODES = new Set([1, 3, 6, 8]);
44
+ function printResult(workspace, result) {
45
+ if (result.status === "completed" || result.stopReason === "completed") {
46
+ const duration = sessionDurationLabel(workspace, result.sessionId);
47
+ log(duration === null ? "completed" : `completed · ${duration}`);
48
+ for (const filePath of artifactPaths(workspace, result.sessionId, result.outputs)) {
49
+ log(`artifact: ${filePath}`);
50
+ }
51
+ return;
52
+ }
53
+ if (INSPECT_EXIT_CODES.has(result.code) && result.latestExecutionId) {
54
+ log(`response: executions/${result.latestExecutionId}/response.md`);
55
+ }
56
+ if (result.code === 7 && result.latestExecutionId) {
57
+ log(`verify: executions/${result.latestExecutionId}/turns/01/verify.md`);
58
+ }
59
+ }
60
+ function artifactPaths(workspace, sessionId, outputs) {
61
+ if (sessionId === "")
62
+ return [];
63
+ const sessionDir = path.resolve(workspace, ".migent", "sessions", sessionId);
64
+ const paths = [];
65
+ for (const [name, value] of Object.entries(outputs)) {
66
+ const record = isRecord(value) ? value : {};
67
+ const relative = typeof record.path === "string" && record.path !== "" ? record.path : path.join("outputs", name);
68
+ paths.push(absoluteFromRoot(path.resolve(sessionDir, relative)));
69
+ }
70
+ return paths;
71
+ }
72
+ function absoluteFromRoot(target) {
73
+ try {
74
+ return realpathSync(target);
75
+ }
76
+ catch {
77
+ return path.resolve(target);
78
+ }
79
+ }
80
+ function sessionDurationLabel(workspace, sessionId) {
81
+ if (sessionId === "")
82
+ return null;
83
+ const executions = path.join(workspace, ".migent", "sessions", sessionId, "executions");
84
+ let names;
85
+ try {
86
+ names = readdirSync(executions);
87
+ }
88
+ catch {
36
89
  return null;
37
- const stripped = value.trim();
38
- return stripped === "" ? null : stripped;
90
+ }
91
+ let total = 0;
92
+ let counted = false;
93
+ for (const name of names) {
94
+ const elapsed = executionElapsedMs(path.join(executions, name, "execution.json"));
95
+ if (elapsed === null)
96
+ continue;
97
+ total += elapsed;
98
+ counted = true;
99
+ }
100
+ return counted ? formatDuration(total) : null;
101
+ }
102
+ function executionElapsedMs(filePath) {
103
+ try {
104
+ const metadata = JSON.parse(readFileSync(filePath, "utf8"));
105
+ if (!isRecord(metadata))
106
+ return null;
107
+ const started = parsedTime(metadata.created_at);
108
+ if (started === null)
109
+ return null;
110
+ return (parsedTime(metadata.completed_at) ?? Date.now()) - started;
111
+ }
112
+ catch {
113
+ return null;
114
+ }
115
+ }
116
+ function parsedTime(value) {
117
+ if (typeof value !== "string" || value === "")
118
+ return null;
119
+ const parsed = Date.parse(value);
120
+ return Number.isNaN(parsed) ? null : parsed;
121
+ }
122
+ function isRecord(value) {
123
+ return typeof value === "object" && value !== null && !Array.isArray(value);
39
124
  }
@@ -18,6 +18,7 @@ export declare function runInit(workspace: string, options?: {
18
18
  model?: string | null;
19
19
  options?: readonly string[];
20
20
  preset?: string;
21
+ presetExplicit?: boolean;
21
22
  skill?: boolean;
22
23
  interactive?: boolean;
23
24
  adapters?: Record<string, AgentAdapter> | null;
@@ -1,7 +1,9 @@
1
- import { mkdirSync, readdirSync, statSync, writeFileSync } from "node:fs";
1
+ import { mkdirSync, readdirSync, writeFileSync } from "node:fs";
2
2
  import path from "node:path";
3
3
  import { confirm as clackConfirm, isCancel, select as clackSelect } from "@clack/prompts";
4
- import { diagnose, whichSync, yamlScalar } from "@nodeint/migent-kernel";
4
+ import { ConfigurationError, diagnose, whichSync, yamlScalar, } from "@nodeint/migent-kernel";
5
+ import { PromptCancelled } from "../errors.js";
6
+ import { exists, isDirectory, isFile } from "../fs-utils.js";
5
7
  import { printAlreadyInitialized, printCreated, printError, printInitConflicts, } from "../display.js";
6
8
  import { cliHooks } from "../hooks.js";
7
9
  import { runDoctor } from "./doctor.js";
@@ -22,11 +24,23 @@ export async function runInit(workspace, options = {}) {
22
24
  printError("preset must be implement or plan.");
23
25
  return 2;
24
26
  }
27
+ const optionPairs = options.options ?? [];
28
+ const classified = classify(workspace, chosen, resolve);
29
+ if (classified.state === "ready") {
30
+ if (provider !== null || model !== null || optionPairs.length > 0) {
31
+ printError("Already initialized; ignoring --provider/--model/--option.");
32
+ }
33
+ if (options.presetExplicit === true)
34
+ printError("Already initialized; ignoring --preset.");
35
+ printAlreadyInitialized();
36
+ if (skill)
37
+ return installSkill(workspace);
38
+ return 0;
39
+ }
25
40
  if ((provider === null) !== (model === null)) {
26
41
  printError("Pass both --provider and --model, or omit both.");
27
42
  return 2;
28
43
  }
29
- const optionPairs = options.options ?? [];
30
44
  if (optionPairs.length > 0 && provider === null) {
31
45
  printError("Pass --provider and --model with --option.");
32
46
  return 2;
@@ -35,13 +49,6 @@ export async function runInit(workspace, options = {}) {
35
49
  printError("Pass --provider and --model when init is not interactive.");
36
50
  return 2;
37
51
  }
38
- const classified = classify(workspace, chosen, resolve);
39
- if (classified.state === "ready") {
40
- printAlreadyInitialized();
41
- if (skill)
42
- return installSkill(workspace);
43
- return 0;
44
- }
45
52
  if (classified.state === "conflict") {
46
53
  printInitConflicts(classified.conflicts);
47
54
  return 1;
@@ -56,6 +63,8 @@ export async function runInit(workspace, options = {}) {
56
63
  });
57
64
  }
58
65
  catch (error) {
66
+ if (error instanceof PromptCancelled)
67
+ throw error;
59
68
  printError(error instanceof Error ? error.message : String(error));
60
69
  return 2;
61
70
  }
@@ -65,6 +74,8 @@ export async function runInit(workspace, options = {}) {
65
74
  install = await prompt.confirm("Install the Migent skill in .agents/skills/migent?");
66
75
  }
67
76
  catch (error) {
77
+ if (error instanceof PromptCancelled)
78
+ throw error;
68
79
  printError(error instanceof Error ? error.message : String(error));
69
80
  return 2;
70
81
  }
@@ -72,8 +83,24 @@ export async function runInit(workspace, options = {}) {
72
83
  if (install && installSkill(workspace) !== 0)
73
84
  return 1;
74
85
  const paths = writeProject(workspace, preset, primary);
75
- printCreated(paths, `migent start ${preset} --task "..."`);
76
- return runDoctor(workspace, { which: resolve });
86
+ printCreated(paths, `migent session run --workflow ${preset} --task "..."`);
87
+ if (interactive) {
88
+ const doctorCode = await runDoctor(workspace, { which: resolve });
89
+ if (doctorCode !== 0)
90
+ writeDoctorProblems(workspace, chosen, resolve);
91
+ }
92
+ else {
93
+ writeDoctorProblems(workspace, chosen, resolve);
94
+ }
95
+ return 0;
96
+ }
97
+ function writeDoctorProblems(workspace, adapters, which) {
98
+ const problems = diagnose(workspace, { adapters, which }).flatMap((check) => check.problems);
99
+ if (problems.length === 0)
100
+ return;
101
+ process.stderr.write("Doctor reported problems:\n");
102
+ for (const problem of problems)
103
+ process.stderr.write(`${problem}\n`);
77
104
  }
78
105
  async function choices(adapters, which, prompt, args) {
79
106
  let provider = args.provider;
@@ -84,7 +111,7 @@ async function choices(adapters, which, prompt, args) {
84
111
  provider = await prompt.selectProvider(rows, "Default provider");
85
112
  const adapter = adapters[provider];
86
113
  if (adapter === undefined)
87
- throw new Error(`Unknown provider: ${provider}.`);
114
+ throw new ConfigurationError(`Unknown provider: ${provider}.`);
88
115
  const catalog = await loadCatalog(adapter, which, args.runCommand);
89
116
  model = await prompt.selectModel(provider, catalog, "Model");
90
117
  stored = await promptOptions(adapter, model, catalog, which, args.runCommand, prompt);
@@ -92,13 +119,13 @@ async function choices(adapters, which, prompt, args) {
92
119
  else {
93
120
  const adapter = requireAdapter(adapters, provider);
94
121
  if (model === null)
95
- throw new Error("Model is required.");
122
+ throw new ConfigurationError("Model is required.");
96
123
  const catalog = await loadCatalog(adapter, which, args.runCommand);
97
124
  model = knownModel(model, catalog);
98
125
  stored = await acceptedOptions(adapter, model, catalog, which, args.runCommand, args.options);
99
126
  }
100
127
  if (model.trim() === "")
101
- throw new Error("Model is required.");
128
+ throw new ConfigurationError("Model is required.");
102
129
  const primary = { provider, model: model.trim(), options: stored };
103
130
  return primary;
104
131
  }
@@ -151,7 +178,7 @@ function renderConfig(preset, primary) {
151
178
  roles = [["developer", "default"]];
152
179
  else
153
180
  roles = [["planner", "default"], ["reviewer", "default"]];
154
- const lines = ["schema_version: 1", "models:"];
181
+ const lines = ["schema_version: 2", "models:"];
155
182
  for (const [name, choice] of models) {
156
183
  lines.push(` ${name}:`, ` provider: ${yamlScalar(choice.provider)}`, ` model: ${yamlScalar(choice.model)}`);
157
184
  const entries = Object.entries(choice.options);
@@ -168,7 +195,7 @@ function renderConfig(preset, primary) {
168
195
  }
169
196
  function renderWorkflow(preset) {
170
197
  if (preset === "implement") {
171
- return ("schema_version: 1\n" +
198
+ return ("schema_version: 2\n" +
172
199
  "id: implement\n" +
173
200
  "stages:\n" +
174
201
  " - id: implement\n" +
@@ -176,11 +203,9 @@ function renderWorkflow(preset) {
176
203
  " depends_on: []\n" +
177
204
  " instructions:\n" +
178
205
  " - Implement the requested change.\n" +
179
- " - Verify the result with relevant checks or tests.\n" +
180
- "completion:\n" +
181
- " stage: implement\n");
206
+ " - Verify the result with relevant checks or tests.\n");
182
207
  }
183
- return ("schema_version: 1\n" +
208
+ return ("schema_version: 2\n" +
184
209
  "id: plan\n" +
185
210
  "stages:\n" +
186
211
  " - id: plan\n" +
@@ -189,6 +214,7 @@ function renderWorkflow(preset) {
189
214
  " max_revisions: 3\n" +
190
215
  " instructions:\n" +
191
216
  " - Analyze the task and write an implementation plan.\n" +
217
+ " - When revising, edit the existing plan.md in place. Do not replace the whole file.\n" +
192
218
  " produces:\n" +
193
219
  " artifact: plan.md\n" +
194
220
  " - id: review-plan\n" +
@@ -197,6 +223,7 @@ function renderWorkflow(preset) {
197
223
  " - plan\n" +
198
224
  " instructions:\n" +
199
225
  " - Review the plan for correctness, missing risks, and unnecessary scope.\n" +
226
+ " - Report every gap of the same kind in one response.\n" +
200
227
  " decision:\n" +
201
228
  " values:\n" +
202
229
  " - approved\n" +
@@ -204,13 +231,10 @@ function renderWorkflow(preset) {
204
231
  " routes:\n" +
205
232
  " approved: complete\n" +
206
233
  " revise: plan\n" +
207
- "completion:\n" +
208
- " stage: review-plan\n" +
209
- " decision: approved\n" +
210
- " outputs:\n" +
211
- " - name: plan\n" +
212
- " from_stage: plan\n" +
213
- " artifact: plan.md\n");
234
+ "outputs:\n" +
235
+ " - name: plan\n" +
236
+ " from_stage: plan\n" +
237
+ " artifact: plan.md\n");
214
238
  }
215
239
  async function promptOptions(adapter, model, catalog, which, runCommand, prompt) {
216
240
  const stored = {};
@@ -232,28 +256,32 @@ function providerOptions(adapter) {
232
256
  class ClackPrompter {
233
257
  async selectProvider(rows, message) {
234
258
  if (rows.length === 0)
235
- throw new Error("No providers are available.");
259
+ throw new ConfigurationError("No providers are available.");
236
260
  const names = new Set(rows.map(([name]) => name));
237
261
  const result = await clackSelect({
238
262
  message,
239
263
  options: rows.map(([name, found]) => ({ value: name, label: `${name} ${found ?? "not found"}` })),
240
264
  initialValue: rows[0]?.[0],
241
265
  });
242
- if (isCancel(result) || typeof result !== "string" || !names.has(result))
243
- throw new Error("Provider is required.");
266
+ if (isCancel(result))
267
+ throw new PromptCancelled();
268
+ if (typeof result !== "string" || !names.has(result))
269
+ throw new ConfigurationError("Provider is required.");
244
270
  return result;
245
271
  }
246
272
  async selectModel(_provider, catalog, message) {
247
273
  if (catalog.ids.length === 0)
248
- throw new Error("Model is required.");
274
+ throw new ConfigurationError("Model is required.");
249
275
  const initial = catalog.defaultId && catalog.ids.includes(catalog.defaultId) ? catalog.defaultId : catalog.ids[0];
250
276
  const result = await clackSelect({
251
277
  message,
252
278
  options: catalog.ids.map((id) => ({ value: id, label: id })),
253
279
  initialValue: initial,
254
280
  });
255
- if (isCancel(result) || !catalog.ids.includes(String(result)))
256
- throw new Error(`Unknown model: ${String(result)}.`);
281
+ if (isCancel(result))
282
+ throw new PromptCancelled();
283
+ if (!catalog.ids.includes(String(result)))
284
+ throw new ConfigurationError(`Unknown model: ${String(result)}.`);
257
285
  return String(result);
258
286
  }
259
287
  async selectOption(name, values, allowDefault) {
@@ -269,40 +297,19 @@ class ClackPrompter {
269
297
  initialValue: allowDefault ? "" : values[0],
270
298
  });
271
299
  const allowed = new Set(allowDefault ? ["", ...values] : values);
272
- if (isCancel(result) || !allowed.has(String(result ?? ""))) {
273
- throw new Error(`Unknown ${name} value: ${String(result)}.`);
300
+ if (isCancel(result))
301
+ throw new PromptCancelled();
302
+ if (!allowed.has(String(result ?? ""))) {
303
+ throw new ConfigurationError(`Unknown ${name} value: ${String(result)}.`);
274
304
  }
275
305
  return result == null ? "" : String(result);
276
306
  }
277
307
  async confirm(message) {
278
308
  const result = await clackConfirm({ message, initialValue: true });
279
- if (isCancel(result) || typeof result !== "boolean")
280
- throw new Error("Answer yes or no.");
309
+ if (isCancel(result))
310
+ throw new PromptCancelled();
311
+ if (typeof result !== "boolean")
312
+ throw new ConfigurationError("Answer yes or no.");
281
313
  return result;
282
314
  }
283
315
  }
284
- function exists(filePath) {
285
- try {
286
- statSync(filePath);
287
- return true;
288
- }
289
- catch {
290
- return false;
291
- }
292
- }
293
- function isFile(filePath) {
294
- try {
295
- return statSync(filePath).isFile();
296
- }
297
- catch {
298
- return false;
299
- }
300
- }
301
- function isDirectory(filePath) {
302
- try {
303
- return statSync(filePath).isDirectory();
304
- }
305
- catch {
306
- return false;
307
- }
308
- }
@@ -0,0 +1 @@
1
+ export declare function prepareWorkflowSession(workspace: string, sessionId: string, workflowId: string, priorSessionId: string | null): number;
@@ -0,0 +1,14 @@
1
+ import { createPreparedSession, log, relativeTaskPath } from "@nodeint/migent-kernel";
2
+ import { requireCurrentSchema } from "../migrate.js";
3
+ export function prepareWorkflowSession(workspace, sessionId, workflowId, priorSessionId) {
4
+ requireCurrentSchema(workspace);
5
+ const id = createPreparedSession(workspace, sessionId, workflowId, priorSessionId);
6
+ const payload = {
7
+ session_id: id,
8
+ status: "prepared",
9
+ task_path: relativeTaskPath(id),
10
+ };
11
+ process.stdout.write(`${JSON.stringify(payload)}\n`);
12
+ log(`session_id: ${id}`);
13
+ return 0;
14
+ }
@@ -0,0 +1 @@
1
+ export declare function repairWorkflowSession(workspace: string, sessionId: string, acceptTask: boolean): number;
@@ -0,0 +1,22 @@
1
+ import { isSessionLockLost, repairSession, SessionLockHeldError } from "@nodeint/migent-kernel";
2
+ import { printError } from "../display.js";
3
+ import { requireCurrentSchema } from "../migrate.js";
4
+ export function repairWorkflowSession(workspace, sessionId, acceptTask) {
5
+ requireCurrentSchema(workspace);
6
+ try {
7
+ const status = repairSession(workspace, sessionId, { acceptTask });
8
+ const payload = {
9
+ session_id: sessionId,
10
+ status: typeof status.status === "string" ? status.status : null,
11
+ };
12
+ process.stdout.write(`${JSON.stringify(payload)}\n`);
13
+ return 0;
14
+ }
15
+ catch (error) {
16
+ if (error instanceof SessionLockHeldError || isSessionLockLost(error)) {
17
+ printError(error.message);
18
+ return 2;
19
+ }
20
+ throw error;
21
+ }
22
+ }
@@ -34,6 +34,7 @@ export async function runServiceStop() {
34
34
  printError(result.message || "Registry service did not stop.");
35
35
  return 1;
36
36
  }
37
+ process.stderr.write(result.outcome === "absent" ? "Not running.\n" : "Stopped.\n");
37
38
  return 0;
38
39
  }
39
40
  export async function runServiceStatus(asJson) {
@@ -48,13 +49,13 @@ export async function runServiceStatus(asJson) {
48
49
  else {
49
50
  process.stdout.write("stopped\n");
50
51
  }
51
- return 0;
52
+ return report.state === "running" ? 0 : 1;
52
53
  }
53
54
  export function parsePort(raw) {
54
55
  if (!/^[0-9]+$/.test(raw))
55
- throw new ConfigurationError("--port must be an integer.");
56
+ throw new ConfigurationError("--port must be an integer from 1 to 65535.");
56
57
  const port = Number(raw);
57
- if (port > 65535)
58
- throw new ConfigurationError("--port must be an integer.");
58
+ if (port < 1 || port > 65535)
59
+ throw new ConfigurationError("--port must be an integer from 1 to 65535.");
59
60
  return port;
60
61
  }
@@ -1,3 +1,26 @@
1
- export declare function listSessions(workspace: string, options?: {
1
+ export interface SessionListOptions {
2
2
  asJson?: boolean;
3
+ workflow?: string | null;
4
+ status?: string | null;
5
+ limit?: number | null;
6
+ latest?: boolean;
7
+ }
8
+ export declare function listSessions(workspace: string, options?: SessionListOptions): number;
9
+ export declare function runSessionMetrics(workspace: string, session: string | undefined, options: {
10
+ asJson: boolean;
11
+ workflow: string | null;
12
+ status: string | null;
13
+ limit: string | null;
3
14
  }): number;
15
+ export declare function runSessions(workspace: string, session: string | undefined, options: {
16
+ asJson: boolean;
17
+ follow: boolean;
18
+ execution: string | null;
19
+ until: boolean;
20
+ cursor: string | undefined;
21
+ exitWhenDone: boolean;
22
+ workflow: string | null;
23
+ status: string | null;
24
+ limit: string | null;
25
+ latest: boolean;
26
+ }): Promise<number>;