@ekaone/json-cli 0.1.1 → 0.1.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/README.md CHANGED
@@ -16,80 +16,164 @@ pnpm install -g @ekaone/json-cli
16
16
  yarn global add @ekaone/json-cli
17
17
  ```
18
18
 
19
- ## Usage
19
+ ## Setup
20
20
 
21
- ```
21
+ ```bash
22
22
  export ANTHROPIC_API_KEY=your_key_here
23
23
  ```
24
24
 
25
+ > Windows PowerShell: `$env:ANTHROPIC_API_KEY="your_key_here"`
26
+
27
+ ---
28
+
29
+ ## Usage
30
+
31
+ ### Single intent
32
+
25
33
  ```bash
26
34
  json-cli "please run tests"
35
+ json-cli "please build"
36
+ json-cli "check git status"
27
37
  ```
28
38
 
29
- ### For local development
39
+ ### Multi-intent the fun part 🔥
40
+
41
+ Chain multiple commands in plain English using **"then"**, **"and"**, **"after that"**:
30
42
 
31
43
  ```bash
32
- pnpm install
44
+ json-cli "run tests and then build"
45
+ ```
46
+
47
+ ```bash
48
+ json-cli "run typecheck, test, and then check git status"
49
+ ```
50
+
51
+ ```bash
52
+ json-cli "please run dev with port 5000"
53
+ ```
54
+
55
+ ```bash
56
+ json-cli "install deps, run tests, then build"
57
+ ```
58
+
59
+ ### Full release flow in one command 🚀
60
+
61
+ ```bash
62
+ json-cli "run tests, build, git add all, commit with message 'release v0.1.0', push, then publish"
33
63
  ```
34
64
 
35
- ### Usage
65
+ ```
66
+ 📋 Plan (6 steps):
67
+ 1. pnpm test → Run test suite
68
+ 2. pnpm build → Build package
69
+ 3. git add . → Stage all changes
70
+ 4. git commit -m "release v0.1.0" → Commit release
71
+ 5. git push → Push to remote
72
+ 6. pnpm publish → Publish to npm
73
+
74
+ Proceed? › y
75
+ ```
76
+
77
+ ### More crazy examples
36
78
 
37
79
  ```bash
38
- # Using Claude (default)
39
- pnpm dev "install deps and run tests"
80
+ # Full dev startup
81
+ json-cli "install deps and run dev on port 3000"
82
+
83
+ # Audit and fix
84
+ json-cli "run npm audit, then update all deps"
85
+
86
+ # Branch and commit workflow
87
+ json-cli "check git status, add all files, commit with message 'feat: add multi-intent support', then push"
88
+
89
+ # Test everything before shipping
90
+ json-cli "run typecheck, run tests, build, then publish"
40
91
 
41
- # Using OpenAI
42
- pnpm dev "run build and publish" --provider openai
92
+ # Clone and install
93
+ json-cli "clone https://github.com/ekaone/json-cli and then install deps"
43
94
 
44
- # Using Ollama (local)
45
- pnpm dev "start dev server" --provider ollama
95
+ # Check before commit
96
+ json-cli "run tests, check git diff, then git add and commit with message 'fix: catalog types'"
97
+
98
+ # Full CI-like flow locally
99
+ json-cli "install deps, run typecheck, run tests, build, git add, commit with message 'ci: local pipeline passed', push"
46
100
  ```
47
101
 
102
+ ---
103
+
48
104
  ## How it works
49
105
 
50
106
  ```
51
- User Prompt
107
+ User Prompt (plain English)
52
108
 
53
109
 
54
110
  AI Provider ← Claude / OpenAI / Ollama
55
-
111
+ extracts ALL intents, sequences them
56
112
 
57
- JSON Plan ← validated by Zod schema
113
+ JSON Plan ← validated by Zod schema (max 10 steps)
58
114
 
59
115
 
60
116
  Catalog Check ← whitelist prevents hallucinated commands
61
117
 
62
118
 
63
- Confirm (y/n) ← user reviews before execution
119
+ Confirm (y/n) ← review the full plan before execution
64
120
 
65
121
 
66
- Runner ← executes steps, streams output live
122
+ Runner ← executes step by step, streams output live
123
+ stops immediately on first failure
67
124
  ```
68
125
 
126
+ ---
127
+
69
128
  ## Allowed commands
70
129
 
71
- | Type | Commands |
72
- |-------|----------|
73
- | pnpm | install, run, build, test, publish, add, remove |
74
- | npm | install, run, build, test, publish, ci |
75
- | yarn | install, run, build, test, publish, add, remove |
76
- | bun | install, run, build, test, publish, add, remove |
77
- | git | init, add, commit, push, pull, clone, status, log |
78
- | shell | any *(requires extra caution)* |
130
+ | Type | Commands |
131
+ |---------|----------|
132
+ | `pnpm` | install, run, build, test, publish, add, remove, update, dlx, why |
133
+ | `npm` | install, run, build, test, publish, ci, init, outdated, audit |
134
+ | `yarn` | install, run, build, test, publish, add, remove, why, upgrade |
135
+ | `bun` | install, run, build, test, publish, add, remove, x, update |
136
+ | `git` | init, add, commit, push, pull, clone, status, log, branch, checkout, merge, diff, stash |
137
+ | `fs` | mkdir, touch, cp, mv, ls `(coming soon)` |
138
+ | `shell` | any *(escape hatch — always requires extra confirmation)* |
139
+
140
+ > **Note:** Flags and arguments are unrestricted — `--port 5000`, `-m "message"`, `--force` etc. are all passed freely. Only the command itself is whitelisted.
141
+
142
+ ---
143
+
144
+ ## AI Providers
145
+
146
+ ```bash
147
+ # Claude (default)
148
+ json-cli "run tests and build"
149
+
150
+ # OpenAI
151
+ json-cli "run tests and build" --provider openai
152
+
153
+ # Ollama (local, no API key needed)
154
+ json-cli "run tests and build" --provider ollama
155
+ ```
79
156
 
80
157
  ## Environment variables
81
158
 
82
159
  ```bash
83
- ANTHROPIC_API_KEY=sk-ant-...
84
- OPENAI_API_KEY=sk-...
160
+ ANTHROPIC_API_KEY=sk-ant-... # for Claude
161
+ OPENAI_API_KEY=sk-... # for OpenAI
85
162
  ```
86
163
 
87
- ## Run tests
164
+ ---
165
+
166
+ ## Local development
88
167
 
89
168
  ```bash
169
+ pnpm install
170
+ pnpm dev "please run tests"
90
171
  pnpm test
172
+ pnpm build
91
173
  ```
92
174
 
175
+ ---
176
+
93
177
  ## License
94
178
 
95
179
  MIT © [Eka Prasetia](https://prasetia.me/)
@@ -100,4 +184,4 @@ MIT © [Eka Prasetia](https://prasetia.me/)
100
184
  - [GitHub Repository](https://github.com/ekaone/json-cli)
101
185
  - [Issue Tracker](https://github.com/ekaone/json-cli/issues)
102
186
 
103
- ⭐ If this library helps you, please consider giving it a star on GitHub!
187
+ ⭐ If this library helps you, please consider giving it a star on GitHub!
package/dist/cli.cjs CHANGED
@@ -117,7 +117,20 @@ var CATALOG = {
117
117
  pnpm: ["install", "run", "build", "test", "publish", "add", "remove"],
118
118
  yarn: ["install", "run", "build", "test", "publish", "add", "remove"],
119
119
  bun: ["install", "run", "build", "test", "publish", "add", "remove"],
120
- git: ["init", "add", "commit", "push", "pull", "clone", "status", "log"],
120
+ git: [
121
+ "init",
122
+ "add",
123
+ "commit",
124
+ "push",
125
+ "pull",
126
+ "clone",
127
+ "status",
128
+ "log",
129
+ "branch",
130
+ "checkout",
131
+ "merge",
132
+ "stash"
133
+ ],
121
134
  shell: ["any"]
122
135
  // escape hatch — always requires extra confirmation
123
136
  };
@@ -168,6 +181,8 @@ Rules:
168
181
  - Use "shell" type only when no other type fits
169
182
  - Keep steps minimal \u2014 don't add unnecessary steps
170
183
  - Each step must have a clear, short description
184
+ - NEVER generate a "cd" step \u2014 each step runs in a separate process so "cd" has no effect
185
+ - If subsequent steps need to run inside a cloned directory, set the "cwd" field instead
171
186
 
172
187
  Respond ONLY with valid JSON matching this exact shape, no markdown, no explanation:
173
188
  {
@@ -202,7 +217,9 @@ ${issues}`);
202
217
  for (const step of result.data.steps) {
203
218
  const check = validateStep(step);
204
219
  if (!check.valid) {
205
- throw new Error(`Step ${step.id} failed catalog validation: ${check.reason}`);
220
+ throw new Error(
221
+ `Step ${step.id} failed catalog validation: ${check.reason}`
222
+ );
206
223
  }
207
224
  }
208
225
  return result.data;
@@ -227,8 +244,13 @@ async function runStep(step) {
227
244
  });
228
245
  return { success: true };
229
246
  } catch (err) {
230
- const message = err instanceof Error ? err.message : String(err);
231
- return { success: false, error: message };
247
+ const parts = [
248
+ `Command: ${bin} ${args.join(" ")}`,
249
+ err?.exitCode ? `Exit code: ${err.exitCode}` : null,
250
+ err?.stderr ? `Reason: ${err.stderr.trim()}` : null,
251
+ !err?.stderr ? err?.message ?? String(err) : null
252
+ ].filter(Boolean).join("\n ");
253
+ return { success: false, error: parts };
232
254
  }
233
255
  }
234
256
  async function runPlan(plan, onStep) {
@@ -245,28 +267,58 @@ async function runPlan(plan, onStep) {
245
267
  }
246
268
 
247
269
  // src/cli.ts
270
+ function showHelp() {
271
+ p.intro("json-cli \u2014 AI-powered CLI task runner");
272
+ p.log.message(`Usage
273
+ json-cli "<your goal>" [options]
274
+ `);
275
+ p.log.message(
276
+ `Options
277
+ --provider <name> AI provider: claude | openai | ollama (default: claude)
278
+ --yes Skip confirmation prompt
279
+ --dry-run Show plan without executing
280
+ --help Show this help message`
281
+ );
282
+ p.log.message(
283
+ `Examples
284
+ json-cli "please run tests"
285
+ json-cli "run tests and build"
286
+ json-cli "run tests and build" --yes
287
+ json-cli "git add, commit with message 'fix: bug', push"
288
+ json-cli "clone https://github.com/user/repo, install deps, run dev"
289
+ json-cli "run tests and publish" --provider openai
290
+ json-cli "run tests" --dry-run`
291
+ );
292
+ p.outro("Docs: https://github.com/ekaone/json-cli");
293
+ }
248
294
  function parseArgs() {
249
295
  const args = process.argv.slice(2);
296
+ if (args.length === 0 || args.includes("--help")) {
297
+ showHelp();
298
+ process.exit(0);
299
+ }
250
300
  const providerFlag = args.indexOf("--provider");
251
301
  const provider = providerFlag !== -1 ? args[providerFlag + 1] : "claude";
302
+ const yes = args.includes("--yes");
303
+ const dryRun = args.includes("--dry-run");
252
304
  const prompt = args.filter(
253
305
  (a, i) => !a.startsWith("--") && (providerFlag === -1 || i !== providerFlag + 1)
254
306
  ).join(" ");
255
307
  if (!prompt) {
256
- console.error(
257
- 'Usage: json-cli "<your goal>" [--provider claude|openai|ollama]'
258
- );
259
- process.exit(1);
308
+ showHelp();
309
+ process.exit(0);
260
310
  }
261
- return { prompt, provider };
311
+ return { prompt, provider, yes, dryRun };
262
312
  }
263
313
  function formatStep(step) {
264
314
  const cmd = step.type === "shell" ? `${step.command} ${step.args.join(" ")}` : `${step.type} ${step.command} ${step.args.join(" ")}`.trim();
265
315
  return `${cmd.padEnd(35)} \u2192 ${step.description}`;
266
316
  }
267
317
  async function main() {
268
- const { prompt, provider: providerName } = parseArgs();
269
- p.intro(`json-cli \u2014 powered by ${providerName}`);
318
+ const { prompt, provider: providerName, yes, dryRun } = parseArgs();
319
+ p.intro(
320
+ `json-cli \u2014 powered by ${providerName}${dryRun ? " (dry run)" : ""}`
321
+ );
270
322
  const spinner2 = p.spinner();
271
323
  spinner2.start("Thinking...");
272
324
  let plan;
@@ -293,10 +345,18 @@ async function main() {
293
345
  "Plan contains shell commands \u2014 review carefully before proceeding."
294
346
  );
295
347
  }
296
- const confirmed = await p.confirm({ message: "Proceed?" });
297
- if (p.isCancel(confirmed) || !confirmed) {
298
- p.cancel("Aborted.");
299
- process.exit(0);
348
+ if (dryRun) {
349
+ p.outro("Dry run complete \u2014 no commands were executed.");
350
+ setTimeout(() => process.exit(0), 50);
351
+ }
352
+ if (!yes) {
353
+ const confirmed = await p.confirm({ message: "Proceed?" });
354
+ if (p.isCancel(confirmed) || !confirmed) {
355
+ p.cancel("Aborted.");
356
+ setTimeout(() => process.exit(0), 50);
357
+ }
358
+ } else {
359
+ p.log.info("Skipping confirmation (--yes)");
300
360
  }
301
361
  console.log("");
302
362
  const result = await runPlan(plan, (step, i, total) => {
@@ -309,7 +369,7 @@ async function main() {
309
369
  `\u274C Failed at step ${result.failedStep?.id}: ${result.failedStep?.description}
310
370
  ${result.error ?? ""}`
311
371
  );
312
- process.exit(1);
372
+ setTimeout(() => process.exit(1), 50);
313
373
  }
314
374
  }
315
375
  main();
package/dist/index.cjs CHANGED
@@ -32,7 +32,20 @@ var CATALOG = {
32
32
  pnpm: ["install", "run", "build", "test", "publish", "add", "remove"],
33
33
  yarn: ["install", "run", "build", "test", "publish", "add", "remove"],
34
34
  bun: ["install", "run", "build", "test", "publish", "add", "remove"],
35
- git: ["init", "add", "commit", "push", "pull", "clone", "status", "log"],
35
+ git: [
36
+ "init",
37
+ "add",
38
+ "commit",
39
+ "push",
40
+ "pull",
41
+ "clone",
42
+ "status",
43
+ "log",
44
+ "branch",
45
+ "checkout",
46
+ "merge",
47
+ "stash"
48
+ ],
36
49
  shell: ["any"]
37
50
  // escape hatch — always requires extra confirmation
38
51
  };
@@ -83,6 +96,8 @@ Rules:
83
96
  - Use "shell" type only when no other type fits
84
97
  - Keep steps minimal \u2014 don't add unnecessary steps
85
98
  - Each step must have a clear, short description
99
+ - NEVER generate a "cd" step \u2014 each step runs in a separate process so "cd" has no effect
100
+ - If subsequent steps need to run inside a cloned directory, set the "cwd" field instead
86
101
 
87
102
  Respond ONLY with valid JSON matching this exact shape, no markdown, no explanation:
88
103
  {
@@ -117,7 +132,9 @@ ${issues}`);
117
132
  for (const step of result.data.steps) {
118
133
  const check = validateStep(step);
119
134
  if (!check.valid) {
120
- throw new Error(`Step ${step.id} failed catalog validation: ${check.reason}`);
135
+ throw new Error(
136
+ `Step ${step.id} failed catalog validation: ${check.reason}`
137
+ );
121
138
  }
122
139
  }
123
140
  return result.data;
@@ -142,8 +159,13 @@ async function runStep(step) {
142
159
  });
143
160
  return { success: true };
144
161
  } catch (err) {
145
- const message = err instanceof Error ? err.message : String(err);
146
- return { success: false, error: message };
162
+ const parts = [
163
+ `Command: ${bin} ${args.join(" ")}`,
164
+ err?.exitCode ? `Exit code: ${err.exitCode}` : null,
165
+ err?.stderr ? `Reason: ${err.stderr.trim()}` : null,
166
+ !err?.stderr ? err?.message ?? String(err) : null
167
+ ].filter(Boolean).join("\n ");
168
+ return { success: false, error: parts };
147
169
  }
148
170
  }
149
171
  async function runPlan(plan, onStep) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/catalog.ts","../src/planner.ts","../src/runner.ts"],"sourcesContent":["/**\n * @file index.ts\n * @description Core entry point for @ekaone/json-cli.\n * @author Eka Prasetia\n * @website https://prasetia.me\n * @license MIT\n */\n\nexport { generatePlan } from \"./planner.js\";\nexport { runPlan } from \"./runner.js\";\nexport type { Plan, Step } from \"./catalog.js\";\nexport type { AIProvider } from \"./providers/types.js\";\n","import { z } from \"zod\";\n\n// ---------------------------------------------------------------------------\n// Allowed commands per type — the whitelist that prevents hallucination\n// ---------------------------------------------------------------------------\nexport const CATALOG = {\n npm: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"ci\"],\n pnpm: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"add\", \"remove\"],\n yarn: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"add\", \"remove\"],\n bun: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"add\", \"remove\"],\n git: [\"init\", \"add\", \"commit\", \"push\", \"pull\", \"clone\", \"status\", \"log\"],\n shell: [\"any\"], // escape hatch — always requires extra confirmation\n} as const;\n\nexport type CommandType = keyof typeof CATALOG;\n\n// ---------------------------------------------------------------------------\n// Zod schemas — Layer 2 defense against hallucinated output\n// ---------------------------------------------------------------------------\nexport const StepSchema = z.object({\n id: z.number(),\n type: z.enum([\"npm\", \"pnpm\", \"yarn\", \"bun\", \"git\", \"shell\"]),\n command: z.string(),\n args: z.array(z.string()).default([]),\n description: z.string(),\n cwd: z.string().optional(), // optional working directory override\n});\n\nexport const PlanSchema = z.object({\n goal: z.string(),\n steps: z.array(StepSchema).min(1).max(10),\n});\n\nexport type Step = z.infer<typeof StepSchema>;\nexport type Plan = z.infer<typeof PlanSchema>;\n\n// ---------------------------------------------------------------------------\n// Catalog validation — Layer 3: check command is in whitelist\n// ---------------------------------------------------------------------------\nexport function validateStep(step: Step): { valid: boolean; reason?: string } {\n const allowed = CATALOG[step.type];\n\n // shell type is always allowed but flagged for extra confirmation\n if (step.type === \"shell\") {\n return { valid: true };\n }\n\n if (!allowed.includes(step.command as never)) {\n return {\n valid: false,\n reason: `\"${step.command}\" is not an allowed command for type \"${step.type}\". Allowed: ${allowed.join(\", \")}`,\n };\n }\n\n return { valid: true };\n}\n\n// ---------------------------------------------------------------------------\n// Build the catalog string injected into AI system prompt\n// ---------------------------------------------------------------------------\nexport function buildCatalogPrompt(): string {\n const lines = Object.entries(CATALOG).map(([type, commands]) => {\n const list = commands[0] === \"any\" ? \"any shell command (use sparingly)\" : commands.join(\", \");\n return ` - ${type}: [${list}]`;\n });\n\n return `Allowed command types and commands:\\n${lines.join(\"\\n\")}`;\n}\n","import { buildCatalogPrompt, PlanSchema, validateStep } from \"./catalog.js\";\nimport type { AIProvider } from \"./providers/types.js\";\nimport type { Plan } from \"./catalog.js\";\n\n// ---------------------------------------------------------------------------\n// System prompt — constrains AI to only produce catalog-valid JSON\n// ---------------------------------------------------------------------------\nfunction buildSystemPrompt(): string {\n return `You are a CLI task planner. Given a user's goal, generate a JSON execution plan.\n\n${buildCatalogPrompt()}\n\nRules:\n- ONLY use command types and commands listed above\n- Prefer pnpm over npm unless the user specifies otherwise\n- Use \"shell\" type only when no other type fits\n- Keep steps minimal — don't add unnecessary steps\n- Each step must have a clear, short description\n\nRespond ONLY with valid JSON matching this exact shape, no markdown, no explanation:\n{\n \"goal\": \"string describing the overall goal\",\n \"steps\": [\n {\n \"id\": 1,\n \"type\": \"pnpm\",\n \"command\": \"run\",\n \"args\": [\"dev\"],\n \"description\": \"Start dev server\"\n }\n ]\n}`;\n}\n\n// ---------------------------------------------------------------------------\n// Main planner function\n// ---------------------------------------------------------------------------\nexport async function generatePlan(userPrompt: string, provider: AIProvider): Promise<Plan> {\n const raw = await provider.generate(userPrompt, buildSystemPrompt());\n\n // Strip markdown fences if any provider wraps output\n const cleaned = raw.replace(/```json|```/g, \"\").trim();\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(cleaned);\n } catch {\n throw new Error(`AI returned invalid JSON:\\n${cleaned}`);\n }\n\n // Layer 2: Zod shape validation\n const result = PlanSchema.safeParse(parsed);\n if (!result.success) {\n const issues = result.error.issues.map((i) => ` - ${i.path.join(\".\")}: ${i.message}`).join(\"\\n\");\n throw new Error(`Plan failed schema validation:\\n${issues}`);\n }\n\n // Layer 3: Catalog whitelist validation\n for (const step of result.data.steps) {\n const check = validateStep(step);\n if (!check.valid) {\n throw new Error(`Step ${step.id} failed catalog validation: ${check.reason}`);\n }\n }\n\n return result.data;\n}\n","import { execa } from \"execa\";\nimport type { Plan, Step } from \"./catalog.js\";\n\n// ---------------------------------------------------------------------------\n// Build the actual shell command from a Step\n// ---------------------------------------------------------------------------\nfunction resolveCommand(step: Step): { bin: string; args: string[] } {\n if (step.type === \"shell\") {\n // shell: command is the binary, args are the args\n return { bin: step.command, args: step.args };\n }\n\n // For npm/pnpm/yarn/bun/git: binary is the type, command + args follow\n return { bin: step.type, args: [step.command, ...step.args] };\n}\n\n// ---------------------------------------------------------------------------\n// Run a single step, streaming stdout/stderr live\n// ---------------------------------------------------------------------------\nexport async function runStep(step: Step): Promise<{ success: boolean; error?: string }> {\n const { bin, args } = resolveCommand(step);\n\n try {\n await execa(bin, args, {\n cwd: step.cwd ?? process.cwd(),\n stdout: \"inherit\", // stream directly to terminal\n stderr: \"inherit\",\n });\n return { success: true };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return { success: false, error: message };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Run the full plan, stopping on first failure\n// ---------------------------------------------------------------------------\nexport async function runPlan(\n plan: Plan,\n onStep: (step: Step, index: number, total: number) => void\n): Promise<{ success: boolean; failedStep?: Step; error?: string }> {\n const total = plan.steps.length;\n\n for (let i = 0; i < total; i++) {\n const step = plan.steps[i];\n onStep(step, i, total);\n\n const result = await runStep(step);\n\n if (!result.success) {\n return { success: false, failedStep: step, error: result.error };\n }\n }\n\n return { success: true };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/catalog.ts","../src/planner.ts","../src/runner.ts"],"sourcesContent":["/**\n * @file index.ts\n * @description Core entry point for @ekaone/json-cli.\n * @author Eka Prasetia\n * @website https://prasetia.me\n * @license MIT\n */\n\nexport { generatePlan } from \"./planner.js\";\nexport { runPlan } from \"./runner.js\";\nexport type { Plan, Step } from \"./catalog.js\";\nexport type { AIProvider } from \"./providers/types.js\";\n","import { z } from \"zod\";\n\n// ---------------------------------------------------------------------------\n// Allowed commands per type — the whitelist that prevents hallucination\n// ---------------------------------------------------------------------------\nexport const CATALOG = {\n npm: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"ci\"],\n pnpm: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"add\", \"remove\"],\n yarn: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"add\", \"remove\"],\n bun: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"add\", \"remove\"],\n git: [\n \"init\",\n \"add\",\n \"commit\",\n \"push\",\n \"pull\",\n \"clone\",\n \"status\",\n \"log\",\n \"branch\",\n \"checkout\",\n \"merge\",\n \"stash\",\n ],\n shell: [\"any\"], // escape hatch — always requires extra confirmation\n} as const;\n\nexport type CommandType = keyof typeof CATALOG;\n\n// ---------------------------------------------------------------------------\n// Zod schemas — Layer 2 defense against hallucinated output\n// ---------------------------------------------------------------------------\nexport const StepSchema = z.object({\n id: z.number(),\n type: z.enum([\"npm\", \"pnpm\", \"yarn\", \"bun\", \"git\", \"shell\"]),\n command: z.string(),\n args: z.array(z.string()).default([]),\n description: z.string(),\n cwd: z.string().optional(), // optional working directory override\n});\n\nexport const PlanSchema = z.object({\n goal: z.string(),\n steps: z.array(StepSchema).min(1).max(10),\n});\n\nexport type Step = z.infer<typeof StepSchema>;\nexport type Plan = z.infer<typeof PlanSchema>;\n\n// ---------------------------------------------------------------------------\n// Catalog validation — Layer 3: check command is in whitelist\n// ---------------------------------------------------------------------------\nexport function validateStep(step: Step): { valid: boolean; reason?: string } {\n const allowed = CATALOG[step.type];\n\n // shell type is always allowed but flagged for extra confirmation\n if (step.type === \"shell\") {\n return { valid: true };\n }\n\n if (!allowed.includes(step.command as never)) {\n return {\n valid: false,\n reason: `\"${step.command}\" is not an allowed command for type \"${step.type}\". Allowed: ${allowed.join(\", \")}`,\n };\n }\n\n return { valid: true };\n}\n\n// ---------------------------------------------------------------------------\n// Build the catalog string injected into AI system prompt\n// ---------------------------------------------------------------------------\nexport function buildCatalogPrompt(): string {\n const lines = Object.entries(CATALOG).map(([type, commands]) => {\n const list =\n commands[0] === \"any\"\n ? \"any shell command (use sparingly)\"\n : commands.join(\", \");\n return ` - ${type}: [${list}]`;\n });\n\n return `Allowed command types and commands:\\n${lines.join(\"\\n\")}`;\n}\n","import { buildCatalogPrompt, PlanSchema, validateStep } from \"./catalog.js\";\nimport type { AIProvider } from \"./providers/types.js\";\nimport type { Plan } from \"./catalog.js\";\n\n// ---------------------------------------------------------------------------\n// System prompt — constrains AI to only produce catalog-valid JSON\n// ---------------------------------------------------------------------------\nfunction buildSystemPrompt(): string {\n return `You are a CLI task planner. Given a user's goal, generate a JSON execution plan.\n\n${buildCatalogPrompt()}\n\nRules:\n- ONLY use command types and commands listed above\n- Prefer pnpm over npm unless the user specifies otherwise\n- Use \"shell\" type only when no other type fits\n- Keep steps minimal — don't add unnecessary steps\n- Each step must have a clear, short description\n- NEVER generate a \"cd\" step — each step runs in a separate process so \"cd\" has no effect\n- If subsequent steps need to run inside a cloned directory, set the \"cwd\" field instead\n\nRespond ONLY with valid JSON matching this exact shape, no markdown, no explanation:\n{\n \"goal\": \"string describing the overall goal\",\n \"steps\": [\n {\n \"id\": 1,\n \"type\": \"pnpm\",\n \"command\": \"run\",\n \"args\": [\"dev\"],\n \"description\": \"Start dev server\"\n }\n ]\n}`;\n}\n\n// ---------------------------------------------------------------------------\n// Main planner function\n// ---------------------------------------------------------------------------\nexport async function generatePlan(\n userPrompt: string,\n provider: AIProvider,\n): Promise<Plan> {\n const raw = await provider.generate(userPrompt, buildSystemPrompt());\n\n // Strip markdown fences if any provider wraps output\n const cleaned = raw.replace(/```json|```/g, \"\").trim();\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(cleaned);\n } catch {\n throw new Error(`AI returned invalid JSON:\\n${cleaned}`);\n }\n\n // Layer 2: Zod shape validation\n const result = PlanSchema.safeParse(parsed);\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => ` - ${i.path.join(\".\")}: ${i.message}`)\n .join(\"\\n\");\n throw new Error(`Plan failed schema validation:\\n${issues}`);\n }\n\n // Layer 3: Catalog whitelist validation\n for (const step of result.data.steps) {\n const check = validateStep(step);\n if (!check.valid) {\n throw new Error(\n `Step ${step.id} failed catalog validation: ${check.reason}`,\n );\n }\n }\n\n return result.data;\n}\n","import { execa } from \"execa\";\nimport type { Plan, Step } from \"./catalog.js\";\n\n// ---------------------------------------------------------------------------\n// Build the actual shell command from a Step\n// ---------------------------------------------------------------------------\nfunction resolveCommand(step: Step): { bin: string; args: string[] } {\n if (step.type === \"shell\") {\n // shell: command is the binary, args are the args\n return { bin: step.command, args: step.args };\n }\n\n // For npm/pnpm/yarn/bun/git: binary is the type, command + args follow\n return { bin: step.type, args: [step.command, ...step.args] };\n}\n\n// ---------------------------------------------------------------------------\n// Run a single step, streaming stdout/stderr live\n// ---------------------------------------------------------------------------\nexport async function runStep(\n step: Step,\n): Promise<{ success: boolean; error?: string }> {\n const { bin, args } = resolveCommand(step);\n\n try {\n await execa(bin, args, {\n cwd: step.cwd ?? process.cwd(),\n stdout: \"inherit\", // stream directly to terminal\n stderr: \"inherit\",\n });\n return { success: true };\n } catch (err: any) {\n const parts = [\n `Command: ${bin} ${args.join(\" \")}`,\n err?.exitCode ? `Exit code: ${err.exitCode}` : null,\n err?.stderr ? `Reason: ${err.stderr.trim()}` : null,\n !err?.stderr ? (err?.message ?? String(err)) : null,\n ]\n .filter(Boolean)\n .join(\"\\n \");\n\n return { success: false, error: parts };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Run the full plan, stopping on first failure\n// ---------------------------------------------------------------------------\nexport async function runPlan(\n plan: Plan,\n onStep: (step: Step, index: number, total: number) => void,\n): Promise<{ success: boolean; failedStep?: Step; error?: string }> {\n const total = plan.steps.length;\n\n for (let i = 0; i < total; i++) {\n const step = plan.steps[i];\n onStep(step, i, total);\n\n const result = await runStep(step);\n\n if (!result.success) {\n return { success: false, failedStep: step, error: result.error };\n }\n }\n\n return { success: true };\n}\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -5,7 +5,20 @@ var CATALOG = {
5
5
  pnpm: ["install", "run", "build", "test", "publish", "add", "remove"],
6
6
  yarn: ["install", "run", "build", "test", "publish", "add", "remove"],
7
7
  bun: ["install", "run", "build", "test", "publish", "add", "remove"],
8
- git: ["init", "add", "commit", "push", "pull", "clone", "status", "log"],
8
+ git: [
9
+ "init",
10
+ "add",
11
+ "commit",
12
+ "push",
13
+ "pull",
14
+ "clone",
15
+ "status",
16
+ "log",
17
+ "branch",
18
+ "checkout",
19
+ "merge",
20
+ "stash"
21
+ ],
9
22
  shell: ["any"]
10
23
  // escape hatch — always requires extra confirmation
11
24
  };
@@ -56,6 +69,8 @@ Rules:
56
69
  - Use "shell" type only when no other type fits
57
70
  - Keep steps minimal \u2014 don't add unnecessary steps
58
71
  - Each step must have a clear, short description
72
+ - NEVER generate a "cd" step \u2014 each step runs in a separate process so "cd" has no effect
73
+ - If subsequent steps need to run inside a cloned directory, set the "cwd" field instead
59
74
 
60
75
  Respond ONLY with valid JSON matching this exact shape, no markdown, no explanation:
61
76
  {
@@ -90,7 +105,9 @@ ${issues}`);
90
105
  for (const step of result.data.steps) {
91
106
  const check = validateStep(step);
92
107
  if (!check.valid) {
93
- throw new Error(`Step ${step.id} failed catalog validation: ${check.reason}`);
108
+ throw new Error(
109
+ `Step ${step.id} failed catalog validation: ${check.reason}`
110
+ );
94
111
  }
95
112
  }
96
113
  return result.data;
@@ -115,8 +132,13 @@ async function runStep(step) {
115
132
  });
116
133
  return { success: true };
117
134
  } catch (err) {
118
- const message = err instanceof Error ? err.message : String(err);
119
- return { success: false, error: message };
135
+ const parts = [
136
+ `Command: ${bin} ${args.join(" ")}`,
137
+ err?.exitCode ? `Exit code: ${err.exitCode}` : null,
138
+ err?.stderr ? `Reason: ${err.stderr.trim()}` : null,
139
+ !err?.stderr ? err?.message ?? String(err) : null
140
+ ].filter(Boolean).join("\n ");
141
+ return { success: false, error: parts };
120
142
  }
121
143
  }
122
144
  async function runPlan(plan, onStep) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/catalog.ts","../src/planner.ts","../src/runner.ts"],"sourcesContent":["import { z } from \"zod\";\n\n// ---------------------------------------------------------------------------\n// Allowed commands per type — the whitelist that prevents hallucination\n// ---------------------------------------------------------------------------\nexport const CATALOG = {\n npm: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"ci\"],\n pnpm: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"add\", \"remove\"],\n yarn: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"add\", \"remove\"],\n bun: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"add\", \"remove\"],\n git: [\"init\", \"add\", \"commit\", \"push\", \"pull\", \"clone\", \"status\", \"log\"],\n shell: [\"any\"], // escape hatch — always requires extra confirmation\n} as const;\n\nexport type CommandType = keyof typeof CATALOG;\n\n// ---------------------------------------------------------------------------\n// Zod schemas — Layer 2 defense against hallucinated output\n// ---------------------------------------------------------------------------\nexport const StepSchema = z.object({\n id: z.number(),\n type: z.enum([\"npm\", \"pnpm\", \"yarn\", \"bun\", \"git\", \"shell\"]),\n command: z.string(),\n args: z.array(z.string()).default([]),\n description: z.string(),\n cwd: z.string().optional(), // optional working directory override\n});\n\nexport const PlanSchema = z.object({\n goal: z.string(),\n steps: z.array(StepSchema).min(1).max(10),\n});\n\nexport type Step = z.infer<typeof StepSchema>;\nexport type Plan = z.infer<typeof PlanSchema>;\n\n// ---------------------------------------------------------------------------\n// Catalog validation — Layer 3: check command is in whitelist\n// ---------------------------------------------------------------------------\nexport function validateStep(step: Step): { valid: boolean; reason?: string } {\n const allowed = CATALOG[step.type];\n\n // shell type is always allowed but flagged for extra confirmation\n if (step.type === \"shell\") {\n return { valid: true };\n }\n\n if (!allowed.includes(step.command as never)) {\n return {\n valid: false,\n reason: `\"${step.command}\" is not an allowed command for type \"${step.type}\". Allowed: ${allowed.join(\", \")}`,\n };\n }\n\n return { valid: true };\n}\n\n// ---------------------------------------------------------------------------\n// Build the catalog string injected into AI system prompt\n// ---------------------------------------------------------------------------\nexport function buildCatalogPrompt(): string {\n const lines = Object.entries(CATALOG).map(([type, commands]) => {\n const list = commands[0] === \"any\" ? \"any shell command (use sparingly)\" : commands.join(\", \");\n return ` - ${type}: [${list}]`;\n });\n\n return `Allowed command types and commands:\\n${lines.join(\"\\n\")}`;\n}\n","import { buildCatalogPrompt, PlanSchema, validateStep } from \"./catalog.js\";\nimport type { AIProvider } from \"./providers/types.js\";\nimport type { Plan } from \"./catalog.js\";\n\n// ---------------------------------------------------------------------------\n// System prompt — constrains AI to only produce catalog-valid JSON\n// ---------------------------------------------------------------------------\nfunction buildSystemPrompt(): string {\n return `You are a CLI task planner. Given a user's goal, generate a JSON execution plan.\n\n${buildCatalogPrompt()}\n\nRules:\n- ONLY use command types and commands listed above\n- Prefer pnpm over npm unless the user specifies otherwise\n- Use \"shell\" type only when no other type fits\n- Keep steps minimal — don't add unnecessary steps\n- Each step must have a clear, short description\n\nRespond ONLY with valid JSON matching this exact shape, no markdown, no explanation:\n{\n \"goal\": \"string describing the overall goal\",\n \"steps\": [\n {\n \"id\": 1,\n \"type\": \"pnpm\",\n \"command\": \"run\",\n \"args\": [\"dev\"],\n \"description\": \"Start dev server\"\n }\n ]\n}`;\n}\n\n// ---------------------------------------------------------------------------\n// Main planner function\n// ---------------------------------------------------------------------------\nexport async function generatePlan(userPrompt: string, provider: AIProvider): Promise<Plan> {\n const raw = await provider.generate(userPrompt, buildSystemPrompt());\n\n // Strip markdown fences if any provider wraps output\n const cleaned = raw.replace(/```json|```/g, \"\").trim();\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(cleaned);\n } catch {\n throw new Error(`AI returned invalid JSON:\\n${cleaned}`);\n }\n\n // Layer 2: Zod shape validation\n const result = PlanSchema.safeParse(parsed);\n if (!result.success) {\n const issues = result.error.issues.map((i) => ` - ${i.path.join(\".\")}: ${i.message}`).join(\"\\n\");\n throw new Error(`Plan failed schema validation:\\n${issues}`);\n }\n\n // Layer 3: Catalog whitelist validation\n for (const step of result.data.steps) {\n const check = validateStep(step);\n if (!check.valid) {\n throw new Error(`Step ${step.id} failed catalog validation: ${check.reason}`);\n }\n }\n\n return result.data;\n}\n","import { execa } from \"execa\";\nimport type { Plan, Step } from \"./catalog.js\";\n\n// ---------------------------------------------------------------------------\n// Build the actual shell command from a Step\n// ---------------------------------------------------------------------------\nfunction resolveCommand(step: Step): { bin: string; args: string[] } {\n if (step.type === \"shell\") {\n // shell: command is the binary, args are the args\n return { bin: step.command, args: step.args };\n }\n\n // For npm/pnpm/yarn/bun/git: binary is the type, command + args follow\n return { bin: step.type, args: [step.command, ...step.args] };\n}\n\n// ---------------------------------------------------------------------------\n// Run a single step, streaming stdout/stderr live\n// ---------------------------------------------------------------------------\nexport async function runStep(step: Step): Promise<{ success: boolean; error?: string }> {\n const { bin, args } = resolveCommand(step);\n\n try {\n await execa(bin, args, {\n cwd: step.cwd ?? process.cwd(),\n stdout: \"inherit\", // stream directly to terminal\n stderr: \"inherit\",\n });\n return { success: true };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return { success: false, error: message };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Run the full plan, stopping on first failure\n// ---------------------------------------------------------------------------\nexport async function runPlan(\n plan: Plan,\n onStep: (step: Step, index: number, total: number) => void\n): Promise<{ success: boolean; failedStep?: Step; error?: string }> {\n const total = plan.steps.length;\n\n for (let i = 0; i < total; i++) {\n const step = plan.steps[i];\n onStep(step, i, total);\n\n const result = await runStep(step);\n\n if (!result.success) {\n return { success: false, failedStep: step, error: result.error };\n }\n }\n\n return { success: true };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/catalog.ts","../src/planner.ts","../src/runner.ts"],"sourcesContent":["import { z } from \"zod\";\n\n// ---------------------------------------------------------------------------\n// Allowed commands per type — the whitelist that prevents hallucination\n// ---------------------------------------------------------------------------\nexport const CATALOG = {\n npm: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"ci\"],\n pnpm: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"add\", \"remove\"],\n yarn: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"add\", \"remove\"],\n bun: [\"install\", \"run\", \"build\", \"test\", \"publish\", \"add\", \"remove\"],\n git: [\n \"init\",\n \"add\",\n \"commit\",\n \"push\",\n \"pull\",\n \"clone\",\n \"status\",\n \"log\",\n \"branch\",\n \"checkout\",\n \"merge\",\n \"stash\",\n ],\n shell: [\"any\"], // escape hatch — always requires extra confirmation\n} as const;\n\nexport type CommandType = keyof typeof CATALOG;\n\n// ---------------------------------------------------------------------------\n// Zod schemas — Layer 2 defense against hallucinated output\n// ---------------------------------------------------------------------------\nexport const StepSchema = z.object({\n id: z.number(),\n type: z.enum([\"npm\", \"pnpm\", \"yarn\", \"bun\", \"git\", \"shell\"]),\n command: z.string(),\n args: z.array(z.string()).default([]),\n description: z.string(),\n cwd: z.string().optional(), // optional working directory override\n});\n\nexport const PlanSchema = z.object({\n goal: z.string(),\n steps: z.array(StepSchema).min(1).max(10),\n});\n\nexport type Step = z.infer<typeof StepSchema>;\nexport type Plan = z.infer<typeof PlanSchema>;\n\n// ---------------------------------------------------------------------------\n// Catalog validation — Layer 3: check command is in whitelist\n// ---------------------------------------------------------------------------\nexport function validateStep(step: Step): { valid: boolean; reason?: string } {\n const allowed = CATALOG[step.type];\n\n // shell type is always allowed but flagged for extra confirmation\n if (step.type === \"shell\") {\n return { valid: true };\n }\n\n if (!allowed.includes(step.command as never)) {\n return {\n valid: false,\n reason: `\"${step.command}\" is not an allowed command for type \"${step.type}\". Allowed: ${allowed.join(\", \")}`,\n };\n }\n\n return { valid: true };\n}\n\n// ---------------------------------------------------------------------------\n// Build the catalog string injected into AI system prompt\n// ---------------------------------------------------------------------------\nexport function buildCatalogPrompt(): string {\n const lines = Object.entries(CATALOG).map(([type, commands]) => {\n const list =\n commands[0] === \"any\"\n ? \"any shell command (use sparingly)\"\n : commands.join(\", \");\n return ` - ${type}: [${list}]`;\n });\n\n return `Allowed command types and commands:\\n${lines.join(\"\\n\")}`;\n}\n","import { buildCatalogPrompt, PlanSchema, validateStep } from \"./catalog.js\";\nimport type { AIProvider } from \"./providers/types.js\";\nimport type { Plan } from \"./catalog.js\";\n\n// ---------------------------------------------------------------------------\n// System prompt — constrains AI to only produce catalog-valid JSON\n// ---------------------------------------------------------------------------\nfunction buildSystemPrompt(): string {\n return `You are a CLI task planner. Given a user's goal, generate a JSON execution plan.\n\n${buildCatalogPrompt()}\n\nRules:\n- ONLY use command types and commands listed above\n- Prefer pnpm over npm unless the user specifies otherwise\n- Use \"shell\" type only when no other type fits\n- Keep steps minimal — don't add unnecessary steps\n- Each step must have a clear, short description\n- NEVER generate a \"cd\" step — each step runs in a separate process so \"cd\" has no effect\n- If subsequent steps need to run inside a cloned directory, set the \"cwd\" field instead\n\nRespond ONLY with valid JSON matching this exact shape, no markdown, no explanation:\n{\n \"goal\": \"string describing the overall goal\",\n \"steps\": [\n {\n \"id\": 1,\n \"type\": \"pnpm\",\n \"command\": \"run\",\n \"args\": [\"dev\"],\n \"description\": \"Start dev server\"\n }\n ]\n}`;\n}\n\n// ---------------------------------------------------------------------------\n// Main planner function\n// ---------------------------------------------------------------------------\nexport async function generatePlan(\n userPrompt: string,\n provider: AIProvider,\n): Promise<Plan> {\n const raw = await provider.generate(userPrompt, buildSystemPrompt());\n\n // Strip markdown fences if any provider wraps output\n const cleaned = raw.replace(/```json|```/g, \"\").trim();\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(cleaned);\n } catch {\n throw new Error(`AI returned invalid JSON:\\n${cleaned}`);\n }\n\n // Layer 2: Zod shape validation\n const result = PlanSchema.safeParse(parsed);\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => ` - ${i.path.join(\".\")}: ${i.message}`)\n .join(\"\\n\");\n throw new Error(`Plan failed schema validation:\\n${issues}`);\n }\n\n // Layer 3: Catalog whitelist validation\n for (const step of result.data.steps) {\n const check = validateStep(step);\n if (!check.valid) {\n throw new Error(\n `Step ${step.id} failed catalog validation: ${check.reason}`,\n );\n }\n }\n\n return result.data;\n}\n","import { execa } from \"execa\";\nimport type { Plan, Step } from \"./catalog.js\";\n\n// ---------------------------------------------------------------------------\n// Build the actual shell command from a Step\n// ---------------------------------------------------------------------------\nfunction resolveCommand(step: Step): { bin: string; args: string[] } {\n if (step.type === \"shell\") {\n // shell: command is the binary, args are the args\n return { bin: step.command, args: step.args };\n }\n\n // For npm/pnpm/yarn/bun/git: binary is the type, command + args follow\n return { bin: step.type, args: [step.command, ...step.args] };\n}\n\n// ---------------------------------------------------------------------------\n// Run a single step, streaming stdout/stderr live\n// ---------------------------------------------------------------------------\nexport async function runStep(\n step: Step,\n): Promise<{ success: boolean; error?: string }> {\n const { bin, args } = resolveCommand(step);\n\n try {\n await execa(bin, args, {\n cwd: step.cwd ?? process.cwd(),\n stdout: \"inherit\", // stream directly to terminal\n stderr: \"inherit\",\n });\n return { success: true };\n } catch (err: any) {\n const parts = [\n `Command: ${bin} ${args.join(\" \")}`,\n err?.exitCode ? `Exit code: ${err.exitCode}` : null,\n err?.stderr ? `Reason: ${err.stderr.trim()}` : null,\n !err?.stderr ? (err?.message ?? String(err)) : null,\n ]\n .filter(Boolean)\n .join(\"\\n \");\n\n return { success: false, error: parts };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Run the full plan, stopping on first failure\n// ---------------------------------------------------------------------------\nexport async function runPlan(\n plan: Plan,\n onStep: (step: Step, index: number, total: number) => void,\n): Promise<{ success: boolean; failedStep?: Step; error?: string }> {\n const total = plan.steps.length;\n\n for (let i = 0; i < total; i++) {\n const step = plan.steps[i];\n onStep(step, i, total);\n\n const result = await runStep(step);\n\n if (!result.success) {\n return { success: false, failedStep: step, error: result.error };\n }\n }\n\n return { success: true };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekaone/json-cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "AI-powered CLI task runner with JSON command plans",
5
5
  "keywords": [
6
6
  "ai",