keystone-cli 0.4.1 → 0.4.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keystone-cli",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "A local-first, declarative, agentic workflow orchestrator built on Bun",
5
5
  "type": "module",
6
6
  "bin": {
@@ -58,4 +58,4 @@
58
58
  "engines": {
59
59
  "bun": ">=1.0.0"
60
60
  }
61
- }
61
+ }
@@ -42,28 +42,22 @@ export const ConfigSchema = z.object({
42
42
  workflows_directory: z.string().default('workflows'),
43
43
  mcp_servers: z
44
44
  .record(
45
- z.discriminatedUnion('type', [
45
+ z.union([
46
+ // Local MCP server (command-based) - type is optional, defaults to 'local'
46
47
  z.object({
47
- type: z.literal('local').default('local'),
48
+ type: z.literal('local').optional().default('local'),
48
49
  command: z.string(),
49
50
  args: z.array(z.string()).optional(),
50
51
  env: z.record(z.string()).optional(),
51
52
  url: z.string().url().optional(),
52
- oauth: z
53
- .object({
54
- scope: z.string().optional(),
55
- })
56
- .optional(),
53
+ oauth: z.union([z.object({ scope: z.string().optional() }), z.literal(false)]).optional(),
57
54
  }),
55
+ // Remote MCP server (URL-based)
58
56
  z.object({
59
57
  type: z.literal('remote'),
60
58
  url: z.string().url(),
61
59
  headers: z.record(z.string()).optional(),
62
- oauth: z
63
- .object({
64
- scope: z.string().optional(),
65
- })
66
- .optional(),
60
+ oauth: z.union([z.object({ scope: z.string().optional() }), z.literal(false)]).optional(),
67
61
  }),
68
62
  ])
69
63
  )
@@ -237,7 +237,7 @@ export async function executeLlmStep(
237
237
  if (step.schema && typeof output === 'string') {
238
238
  try {
239
239
  const { extractJson } = await import('../utils/json-parser');
240
- output = extractJson(output);
240
+ output = extractJson(output) as typeof output;
241
241
  } catch (e) {
242
242
  throw new Error(
243
243
  `Failed to parse LLM output as JSON matching schema: ${e instanceof Error ? e.message : String(e)}\nOutput: ${output}`
@@ -81,7 +81,7 @@ describe('MCPServer', () => {
81
81
  },
82
82
  });
83
83
 
84
- expect(JSON.parse(response.result.content[0].text).status).toBe('success');
84
+ expect(JSON.parse(response?.result?.content?.[0]?.text || '{}').status).toBe('success');
85
85
  });
86
86
 
87
87
  it('should handle run_workflow failure', async () => {
@@ -130,7 +130,7 @@ describe('MCPServer', () => {
130
130
  },
131
131
  });
132
132
 
133
- const result = JSON.parse(response?.result?.content?.[0]?.text);
133
+ const result = JSON.parse(response?.result?.content?.[0]?.text || '{}');
134
134
  expect(result.status).toBe('paused');
135
135
  expect(result.run_id).toBe('run123');
136
136
  expect(result.message).toBe('Input needed');
@@ -163,7 +163,7 @@ describe('MCPServer', () => {
163
163
  },
164
164
  });
165
165
 
166
- expect(JSON.parse(response.result.content[0].text).status).toBe('success');
166
+ expect(JSON.parse(response?.result?.content?.[0]?.text || '{}').status).toBe('success');
167
167
 
168
168
  // Verify DB was updated
169
169
  const steps = db.getStepsByRun(runId);
@@ -187,7 +187,7 @@ describe('MCPServer', () => {
187
187
  params: { name: 'get_run_logs', arguments: { run_id: runId } },
188
188
  });
189
189
 
190
- const summary = JSON.parse(response?.result?.content?.[0]?.text);
190
+ const summary = JSON.parse(response?.result?.content?.[0]?.text || '{}');
191
191
  expect(summary.workflow).toBe('test-wf');
192
192
  expect(summary.steps).toHaveLength(1);
193
193
  expect(summary.steps[0].step).toBe('s1');
@@ -276,7 +276,7 @@ describe('MCPServer', () => {
276
276
  },
277
277
  });
278
278
 
279
- const result = JSON.parse(response?.result?.content?.[0]?.text);
279
+ const result = JSON.parse(response?.result?.content?.[0]?.text || '{}');
280
280
  expect(result.status).toBe('running');
281
281
  expect(result.run_id).toBe('async-run-123');
282
282
  expect(result.hint).toContain('get_run_status');
@@ -294,7 +294,7 @@ describe('MCPServer', () => {
294
294
  params: { name: 'get_run_status', arguments: { run_id: runId } },
295
295
  });
296
296
 
297
- const status = JSON.parse(response?.result?.content?.[0]?.text);
297
+ const status = JSON.parse(response?.result?.content?.[0]?.text || '{}');
298
298
  expect(status.run_id).toBe(runId);
299
299
  expect(status.workflow).toBe('test-wf');
300
300
  expect(status.status).toBe('running');
@@ -313,7 +313,7 @@ describe('MCPServer', () => {
313
313
  params: { name: 'get_run_status', arguments: { run_id: runId } },
314
314
  });
315
315
 
316
- const status = JSON.parse(response?.result?.content?.[0]?.text);
316
+ const status = JSON.parse(response?.result?.content?.[0]?.text || '{}');
317
317
  expect(status.status).toBe('completed');
318
318
  expect(status.outputs).toEqual({ output: 'done' });
319
319
  expect(status.hint).toBeUndefined();
@@ -331,7 +331,7 @@ describe('MCPServer', () => {
331
331
  params: { name: 'get_run_status', arguments: { run_id: runId } },
332
332
  });
333
333
 
334
- const status = JSON.parse(response?.result?.content?.[0]?.text);
334
+ const status = JSON.parse(response?.result?.content?.[0]?.text || '{}');
335
335
  expect(status.status).toBe('failed');
336
336
  expect(status.error).toBe('Something went wrong');
337
337
  });
@@ -348,7 +348,7 @@ describe('MCPServer', () => {
348
348
  params: { name: 'get_run_status', arguments: { run_id: runId } },
349
349
  });
350
350
 
351
- const status = JSON.parse(response?.result?.content?.[0]?.text);
351
+ const status = JSON.parse(response?.result?.content?.[0]?.text || '{}');
352
352
  expect(status.status).toBe('paused');
353
353
  expect(status.hint).toContain('answer_human_input');
354
354
  });