keystone-cli 1.0.0 → 1.0.2

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 CHANGED
@@ -133,14 +133,17 @@ keystone ui
133
133
 
134
134
  `keystone init` seeds these workflows under `.keystone/workflows/` (and the agents they rely on under `.keystone/workflows/agents/`):
135
135
 
136
+ Top-level workflows:
136
137
  - `scaffold-feature`: Interactive workflow scaffolder. Prompts for requirements, plans files, generates content, and writes them.
138
+ - `decompose-problem`: Decomposes a problem into research/implementation/review tasks, waits for approval, runs sub-workflows, and summarizes.
139
+ - `dev`: Self-bootstrapping DevMode workflow for an interactive plan/implement/verify loop.
140
+
141
+ Sub-workflows:
137
142
  - `scaffold-plan`: Generates a file plan from `requirements` input.
138
143
  - `scaffold-generate`: Generates file contents from `requirements` plus a `files` plan.
139
- - `decompose-problem`: Decomposes a problem into research/implementation/review tasks, waits for approval, runs sub-workflows, and summarizes.
140
144
  - `decompose-research`: Runs a single research task (`task`) with optional `context`/`constraints`.
141
145
  - `decompose-implement`: Runs a single implementation task (`task`) with optional `research` findings.
142
146
  - `decompose-review`: Reviews a single implementation task (`task`) with optional `implementation` results.
143
- - `dev`: Self-bootstrapping DevMode workflow for an interactive plan/implement/verify loop.
144
147
 
145
148
  Example runs:
146
149
  ```bash
@@ -148,7 +151,7 @@ keystone run scaffold-feature
148
151
  keystone run decompose-problem -i problem="Add caching to the API" -i context="Node/Bun service"
149
152
  ```
150
153
 
151
- The sub-workflows are used by the top-level workflows, but can be run directly if you want just one phase.
154
+ Sub-workflows are used by the top-level workflows, but can be run directly if you want just one phase.
152
155
 
153
156
  ---
154
157
 
@@ -258,7 +261,7 @@ model: claude-3-5-sonnet-latest
258
261
  ```
259
262
 
260
263
  ### OpenAI Compatible Providers
261
- You can add any OpenAI-compatible provider (Groq, Together AI, Perplexity, Local Ollama, etc.) by setting the `type` to `openai` and providing the `base_url` and `api_key_env`.
264
+ You can add any OpenAI-compatible provider (Together AI, Perplexity, Local Ollama, etc.) by setting the `type` to `openai` and providing the `base_url` and `api_key_env`.
262
265
 
263
266
  ### GitHub Copilot Support
264
267
 
@@ -476,7 +479,7 @@ All steps support common features:
476
479
  - `transform`: Post-process output using expressions.
477
480
  - `learn`: Auto-index for few-shot.
478
481
  - `reflexion`: Self-correction loop.
479
- - `auto_heal`: LLM-powered automatic error recovery (alias: `autoHeal`).
482
+ - `auto_heal`: LLM-powered automatic error recovery.
480
483
  - `inputSchema` / `outputSchema`: JSON Schema validation.
481
484
  - `outputRetries`: Max retries for output validation failures.
482
485
  - `repairStrategy`: Strategy for output repair (`reask`, `repair`, `hybrid`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keystone-cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "A local-first, declarative, agentic workflow orchestrator built on Bun",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,4 +1,4 @@
1
- import type { Database } from 'bun:sqlite';
1
+ import { Database } from 'bun:sqlite';
2
2
  import { randomUUID } from 'node:crypto';
3
3
  import { existsSync, mkdirSync } from 'node:fs';
4
4
  import { dirname } from 'node:path';
@@ -24,7 +24,6 @@ export class MemoryDb {
24
24
  cached.refCount++;
25
25
  this.db = cached.db;
26
26
  } else {
27
- const { Database } = require('bun:sqlite');
28
27
  const dir = dirname(dbPath);
29
28
  if (!existsSync(dir)) {
30
29
  mkdirSync(dir, { recursive: true });
@@ -1,3 +1,5 @@
1
+ import { Database } from 'bun:sqlite';
2
+ import { existsSync } from 'node:fs';
1
3
  import { ConsoleLogger, type Logger } from '../utils/logger.ts';
2
4
 
3
5
  export function setupSqlite(logger: Logger = new ConsoleLogger()) {
@@ -5,9 +7,6 @@ export function setupSqlite(logger: Logger = new ConsoleLogger()) {
5
7
  // We need to try to load a custom one (e.g. from Homebrew) if on macOS
6
8
  if (process.platform === 'darwin') {
7
9
  try {
8
- const { Database } = require('bun:sqlite');
9
- const { existsSync } = require('node:fs');
10
-
11
10
  // Common Homebrew paths for SQLite
12
11
  const paths = [
13
12
  '/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib',
@@ -325,9 +325,7 @@ export async function executeEngineStep(
325
325
  throw new Error(`Engine command "${command}" is not in the allowlist. Allowed: ${allowedList}`);
326
326
  }
327
327
 
328
- const versionArgs = allowlistMatch.entry.versionArgs?.length
329
- ? allowlistMatch.entry.versionArgs
330
- : ['--version'];
328
+ const versionArgs = allowlistMatch.entry.versionArgs ?? ['--version'];
331
329
  const versionOutput = await checkEngineVersion(command, versionArgs, env, cwd, abortSignal);
332
330
  if (!versionOutput.includes(allowlistMatch.entry.version)) {
333
331
  throw new Error(
@@ -12,7 +12,7 @@ You are the Keystone Architect. Your goal is to design and generate high-quality
12
12
  ## Workflow Schema (.yaml)
13
13
  - **name**: Unique identifier for the workflow.
14
14
  - **description**: (Optional) Description of the workflow.
15
- - **inputs**: Map of `{ type: 'string'|'number'|'boolean'|'array'|'object', default: any, description: string }` under the `inputs` key.
15
+ - **inputs**: Map of `{ type: 'string'|'number'|'boolean'|'array'|'object', default: any, description?: string }` under the `inputs` key.
16
16
  - **outputs**: Map of expressions (e.g., `${{ steps.id.output }}`) under the `outputs` key.
17
17
  - **outputSchema**: (Optional) JSON Schema for final workflow outputs.
18
18
  - **env**: (Optional) Map of workflow-level environment variables.
@@ -59,7 +59,7 @@ Markdown files with YAML frontmatter:
59
59
  ## Expression Syntax
60
60
  - `${{ inputs.name }}`
61
61
  - `${{ steps.id.output }}`
62
- - `${{ steps.id.status }}` (e.g., `'pending'`, `'running'`, `'success'`, `'failed'`, `'skipped'`)
62
+ - `${{ steps.id.status }}` (e.g., `'pending'`, `'running'`, `'success'`, `'failed'`, `'paused'`, `'suspended'`, `'skipped'`, `'canceled'`, `'waiting'`)
63
63
  - `${{ args.paramName }}` (used inside agent tools)
64
64
  - `${{ item }}` (current item in a `foreach` loop)
65
65
  - `${{ secrets.NAME }}` (access redacted secrets)
@@ -5,7 +5,7 @@ inputs:
5
5
  target_dir: { type: string, default: "./data" }
6
6
 
7
7
  outputs:
8
- processed_count: ${{ steps.process_files.outputs.length }}
8
+ processed_count: ${{ steps.process_files.output.length }}
9
9
 
10
10
  env:
11
11
  API_KEY: ${{ secrets.API_KEY }}
@@ -3,7 +3,7 @@ description: "Test the foreach race condition fix and .every() support"
3
3
 
4
4
  outputs:
5
5
  all_success: ${{ steps.process_items.items.every(s => s.status == 'success') }}
6
- item_count: ${{ steps.process_items.outputs.length }}
6
+ item_count: ${{ steps.process_items.output.length }}
7
7
  first_output: ${{ steps.process_items.items[0].output }}
8
8
 
9
9
  steps:
@@ -39,16 +39,16 @@ describe('ResourceLoader', () => {
39
39
  expect(ResourceLoader.isDirectory(testFile)).toBe(false);
40
40
  });
41
41
 
42
- test('should have embedded assets from repo during tests', () => {
42
+ test('should expose embedded assets manifest when available', () => {
43
43
  const assets = ResourceLoader.getEmbeddedAssets();
44
44
  const keys = Object.keys(assets);
45
- // We expect at least the default seeded workflows if they exist in .keystone
46
- expect(keys.length).toBeGreaterThan(0);
47
45
 
48
- // Check for a common seeded workflow if it exists
49
- const hasScaffold = keys.some((k) => k.includes('scaffold-feature.yaml'));
50
- if (hasScaffold) {
51
- expect(hasScaffold).toBe(true);
46
+ // Bundled assets only exist in compiled builds; dev/test may be empty.
47
+ if (keys.length === 0) {
48
+ expect(keys.length).toBe(0);
49
+ return;
52
50
  }
51
+
52
+ expect(Object.values(assets).every((value) => typeof value === 'string')).toBe(true);
53
53
  });
54
54
  });