@_davideast/jules-env 0.0.2 → 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 (3) hide show
  1. package/README.md +9 -4
  2. package/dist/cli.mjs +163 -34
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -23,6 +23,10 @@ Wrote .jules/shellenv
23
23
  2. **Plan** — The recipe produces an execution plan: shell commands to run, environment variables to set, and paths to prepend.
24
24
  3. **Execute** — The plan runs. Install steps that are already satisfied (checked via an optional `checkCmd`) are skipped. State is persisted to `.jules/shellenv`.
25
25
 
26
+ ### Data recipes
27
+
28
+ Recipes can also be defined as JSON files. A data recipe is a static execution plan — no system probing, no dynamic resolution. This makes them easy to generate programmatically (e.g., by an LLM). Data recipes are validated against a Zod schema at load time. See `src/recipes/ollama.json` for an example.
29
+
26
30
  ## Shell environment
27
31
 
28
32
  After execution, `.jules/shellenv` contains the environment your runtime needs:
@@ -69,9 +73,10 @@ jules-env use dart --dry-run
69
73
 
70
74
  ## Available recipes
71
75
 
72
- | Runtime | Recipe | Install method | Description |
73
- |---------|--------|---------------|-------------|
74
- | Dart | `dart` | Homebrew | Installs the Dart SDK via `brew install dart-sdk` |
76
+ | Runtime | Recipe | Type | Description |
77
+ |---------|--------|------|-------------|
78
+ | Dart | `dart` | Code | Installs the Dart SDK (Homebrew on macOS, apt on Linux) |
79
+ | Ollama | `ollama` | Data | Installs Ollama with EmbeddingGemma model |
75
80
 
76
81
  ## Installation
77
82
 
@@ -95,7 +100,7 @@ bun run build
95
100
  ### Prerequisites
96
101
 
97
102
  - [Bun](https://bun.sh/)
98
- - [Homebrew](https://brew.sh/) (required for the Dart recipe)
103
+ - [Homebrew](https://brew.sh/) (macOS only, used by Dart recipe)
99
104
 
100
105
  ### Run tests
101
106
 
package/dist/cli.mjs CHANGED
@@ -6011,6 +6011,18 @@ var ExecutionPlanSchema = z.object({
6011
6011
  content: z.string()
6012
6012
  })).default([])
6013
6013
  });
6014
+ var DataRecipeSchema = z.object({
6015
+ name: z.string(),
6016
+ description: z.string(),
6017
+ defaultPreset: z.string().optional(),
6018
+ installSteps: z.array(ShellStepSchema),
6019
+ env: z.record(z.string()).default({}),
6020
+ paths: z.array(z.string()).default([]),
6021
+ files: z.array(z.object({
6022
+ path: z.string(),
6023
+ content: z.string()
6024
+ })).default([])
6025
+ });
6014
6026
 
6015
6027
  // src/core/executor.ts
6016
6028
  import { spawn } from "node:child_process";
@@ -6031,8 +6043,7 @@ async function executePlan(plan, dryRun) {
6031
6043
  console.log(`[${step.id}] ${step.label}...`);
6032
6044
  let skip = false;
6033
6045
  if (step.checkCmd) {
6034
- const checkParts = step.checkCmd.split(" ");
6035
- const check = spawn(checkParts[0], checkParts.slice(1), {
6046
+ const check = spawn("sh", ["-c", step.checkCmd], {
6036
6047
  stdio: "ignore"
6037
6048
  });
6038
6049
  const exitCode = await new Promise((res) => check.on("close", (code) => res(code ?? 1)));
@@ -6042,8 +6053,7 @@ async function executePlan(plan, dryRun) {
6042
6053
  }
6043
6054
  }
6044
6055
  if (!skip) {
6045
- const cmdParts = step.cmd.split(" ");
6046
- const proc = spawn(cmdParts[0], cmdParts.slice(1), {
6056
+ const proc = spawn("sh", ["-c", step.cmd], {
6047
6057
  stdio: "inherit"
6048
6058
  });
6049
6059
  const exitCode = await new Promise((res) => proc.on("close", (code) => res(code ?? 1)));
@@ -6088,43 +6098,161 @@ async function executePlan(plan, dryRun) {
6088
6098
 
6089
6099
  // src/recipes/dart.ts
6090
6100
  import { spawnSync } from "node:child_process";
6101
+ async function resolveDarwin() {
6102
+ const installSteps = [{
6103
+ id: "install-dart",
6104
+ label: "Install Dart SDK",
6105
+ cmd: "brew install dart-sdk",
6106
+ checkCmd: "brew list --versions dart-sdk"
6107
+ }];
6108
+ let dartPrefix = "";
6109
+ try {
6110
+ const result = spawnSync("brew", ["--prefix", "dart-sdk"], { encoding: "utf-8" });
6111
+ if (result.status === 0) {
6112
+ dartPrefix = result.stdout.trim();
6113
+ }
6114
+ } catch (e) {}
6115
+ if (!dartPrefix) {
6116
+ dartPrefix = "/usr/local/opt/dart-sdk";
6117
+ }
6118
+ const env = {
6119
+ DART_SDK: `${dartPrefix}/libexec`
6120
+ };
6121
+ const paths = [
6122
+ `${dartPrefix}/bin`
6123
+ ];
6124
+ return ExecutionPlanSchema.parse({ installSteps, env, paths });
6125
+ }
6126
+ async function resolveLinux() {
6127
+ const installSteps = [
6128
+ {
6129
+ id: "install-dart-prereqs",
6130
+ label: "Install prerequisites",
6131
+ cmd: "sudo apt-get update && sudo apt-get install -y apt-transport-https wget",
6132
+ checkCmd: "dpkg -s apt-transport-https && dpkg -s wget"
6133
+ },
6134
+ {
6135
+ id: "add-dart-signing-key",
6136
+ label: "Add Dart signing key",
6137
+ cmd: "wget -qO- https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo gpg --dearmor -o /usr/share/keyrings/dart.gpg",
6138
+ checkCmd: "test -f /usr/share/keyrings/dart.gpg"
6139
+ },
6140
+ {
6141
+ id: "add-dart-repo",
6142
+ label: "Add Dart repository",
6143
+ cmd: "echo 'deb [signed-by=/usr/share/keyrings/dart.gpg arch=amd64] https://storage.googleapis.com/dart-archive/channels/stable/release/latest/linux/debian stable main' | sudo tee /etc/apt/sources.list.d/dart_stable.list > /dev/null",
6144
+ checkCmd: "test -f /etc/apt/sources.list.d/dart_stable.list"
6145
+ },
6146
+ {
6147
+ id: "install-dart",
6148
+ label: "Install Dart SDK",
6149
+ cmd: "sudo apt-get update && sudo apt-get install -y dart",
6150
+ checkCmd: "dpkg -s dart"
6151
+ }
6152
+ ];
6153
+ const env = {
6154
+ DART_SDK: "/usr/lib/dart"
6155
+ };
6156
+ const paths = [
6157
+ "/usr/lib/dart/bin"
6158
+ ];
6159
+ return ExecutionPlanSchema.parse({ installSteps, env, paths });
6160
+ }
6091
6161
  var DartRecipe = {
6092
6162
  name: "dart",
6093
- description: "Dart SDK via Homebrew",
6163
+ description: "Dart SDK",
6094
6164
  resolve: async (ctx) => {
6095
- const installSteps = [{
6096
- id: "install-dart",
6097
- label: "Install Dart SDK",
6098
- cmd: "brew install dart-sdk",
6099
- checkCmd: "brew list --versions dart-sdk"
6100
- }];
6101
- let dartPrefix = "";
6102
- try {
6103
- const result = spawnSync("brew", ["--prefix", "dart-sdk"], { encoding: "utf-8" });
6104
- if (result.status === 0) {
6105
- dartPrefix = result.stdout.trim();
6106
- }
6107
- } catch (e) {}
6108
- if (!dartPrefix) {
6109
- dartPrefix = "/usr/local/opt/dart-sdk";
6110
- }
6111
- const env = {
6112
- DART_SDK: `${dartPrefix}/libexec`
6113
- };
6114
- const paths = [
6115
- `${dartPrefix}/bin`
6116
- ];
6117
- return ExecutionPlanSchema.parse({
6118
- installSteps,
6119
- env,
6120
- paths
6121
- });
6165
+ switch (process.platform) {
6166
+ case "darwin":
6167
+ return resolveDarwin();
6168
+ case "linux":
6169
+ return resolveLinux();
6170
+ default:
6171
+ throw new Error(`Unsupported platform: ${process.platform}`);
6172
+ }
6122
6173
  }
6123
6174
  };
6175
+
6176
+ // src/core/loader.ts
6177
+ function substituteVars(str, vars) {
6178
+ return str.replace(/\{\{(\w+)\}\}/g, (_, key) => {
6179
+ const val = vars[key];
6180
+ if (val === undefined) {
6181
+ throw new Error(`Missing required variable: {{${key}}}. Pass --preset to provide a value.`);
6182
+ }
6183
+ return val;
6184
+ });
6185
+ }
6186
+ function loadDataRecipe(data) {
6187
+ const parsed = DataRecipeSchema.parse(data);
6188
+ return {
6189
+ name: parsed.name,
6190
+ description: parsed.description,
6191
+ resolve: async (ctx) => {
6192
+ const vars = {};
6193
+ const preset = ctx.preset ?? parsed.defaultPreset;
6194
+ if (preset) {
6195
+ vars["preset"] = preset;
6196
+ }
6197
+ const installSteps = parsed.installSteps.map((step) => ({
6198
+ id: substituteVars(step.id, vars),
6199
+ label: substituteVars(step.label, vars),
6200
+ cmd: substituteVars(step.cmd, vars),
6201
+ ...step.checkCmd ? { checkCmd: substituteVars(step.checkCmd, vars) } : {}
6202
+ }));
6203
+ return {
6204
+ installSteps,
6205
+ env: parsed.env,
6206
+ paths: parsed.paths,
6207
+ files: parsed.files
6208
+ };
6209
+ }
6210
+ };
6211
+ }
6212
+ // src/recipes/ollama.json
6213
+ var ollama_default = {
6214
+ name: "ollama",
6215
+ description: "Ollama with configurable model",
6216
+ installSteps: [
6217
+ {
6218
+ id: "install-zstd",
6219
+ label: "Install zstd",
6220
+ cmd: "sudo apt-get update && sudo apt-get install -y zstd",
6221
+ checkCmd: "dpkg -s zstd"
6222
+ },
6223
+ {
6224
+ id: "install-ollama",
6225
+ label: "Install Ollama",
6226
+ cmd: "curl -fsSL https://ollama.com/install.sh | sh",
6227
+ checkCmd: "which ollama"
6228
+ },
6229
+ {
6230
+ id: "enable-ollama",
6231
+ label: "Enable Ollama service",
6232
+ cmd: "sudo systemctl daemon-reload && sudo systemctl enable --now ollama",
6233
+ checkCmd: "systemctl is-active ollama"
6234
+ },
6235
+ {
6236
+ id: "wait-for-ollama",
6237
+ label: "Wait for Ollama to initialize",
6238
+ cmd: "sleep 5"
6239
+ },
6240
+ {
6241
+ id: "pull-model",
6242
+ label: "Pull {{preset}} model",
6243
+ cmd: "ollama pull {{preset}}",
6244
+ checkCmd: "ollama list | grep {{preset}}"
6245
+ }
6246
+ ],
6247
+ env: {
6248
+ OLLAMA_HOST: "http://localhost:11434"
6249
+ },
6250
+ paths: []
6251
+ };
6124
6252
  // package.json
6125
6253
  var package_default = {
6126
6254
  name: "@_davideast/jules-env",
6127
- version: "0.0.2",
6255
+ version: "0.1.0",
6128
6256
  description: "Configure ephemeral development environments",
6129
6257
  license: "Apache-2.0",
6130
6258
  type: "module",
@@ -6164,7 +6292,8 @@ var package_default = {
6164
6292
  // src/cli.ts
6165
6293
  var program2 = new Command;
6166
6294
  var recipes = {
6167
- dart: DartRecipe
6295
+ dart: DartRecipe,
6296
+ ollama: loadDataRecipe(ollama_default)
6168
6297
  };
6169
6298
  program2.name("jules-env").description("Configure ephemeral development environments").version(package_default.version);
6170
6299
  program2.command("use <runtime>").description("Setup a runtime environment").option("--version <v>", "Version to install", "latest").option("--dry-run", "Simulate execution", false).option("--preset <p>", "Configuration preset").action(async (runtime, options) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@_davideast/jules-env",
3
- "version": "0.0.2",
3
+ "version": "0.1.0",
4
4
  "description": "Configure ephemeral development environments",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",