jules-orchestrator-kit 0.8.0 → 0.8.5

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.
@@ -1,9 +1,5 @@
1
1
  {
2
2
  "rules": [
3
- {
4
- "trigger": "\\.astro",
5
- "guardrail": "## 🟢 ASTRO GUARDRAILS\n- DO NOT run `biome check --write --unsafe` on `.astro` files (destroys frontmatter).\n- DO NOT import 'sharp' into runtime bundles."
6
- },
7
3
  {
8
4
  "trigger": "\\b(db|database|drizzle|sql\\w*|postgres\\w*|sqlite\\w*|mysql\\w*)\\b",
9
5
  "guardrail": "## 🗄️ DATABASE GUARDRAILS\n- Always batch multiple database statements.\n- DO NOT write destructive migrations (`DROP TABLE`) without explicit user consent."
package/.env.example CHANGED
@@ -27,6 +27,9 @@ JULES_REPO=owner/repo
27
27
  # Allow modifications to command-defining files (package.json, Cargo.toml, etc.) in PRs (Default: false)
28
28
  # JULES_ALLOW_COMMAND_FILE_CHANGES=false
29
29
 
30
+ # Allow modifications to agent rule files (AGENTS.md, JULES_RULES_TEMPLATE.md, .agent/rules/**) in PRs (Default: false)
31
+ # JULES_ALLOW_AGENT_RULE_CHANGES=false
32
+
30
33
  # --- Execution Scope & Git ---
31
34
  # Base Branch for PR Audits & Merge-Base Calculations (Default: main)
32
35
  BASE_BRANCH=main
@@ -11,7 +11,7 @@ jobs:
11
11
  runs-on: ubuntu-latest
12
12
  strategy:
13
13
  matrix:
14
- node-version: ['18.x', '20.x', '22.x', '24.x']
14
+ node-version: ['22.x', '24.x']
15
15
  steps:
16
16
  - name: Checkout repository
17
17
  uses: actions/checkout@v4
@@ -23,14 +23,25 @@ jobs:
23
23
  with:
24
24
  node-version: ${{ matrix.node-version }}
25
25
 
26
- - name: Syntax Check
27
- run: for f in scripts/*.mjs bin/*.js index.mjs; do node --check "$f" || exit 1; done
26
+ - name: Cache OODA state & ledgers
27
+ uses: actions/cache@v4
28
+ with:
29
+ path: .agent/state/
30
+ key: ooda-state-${{ runner.os }}-${{ github.run_id }}
31
+ restore-keys: |
32
+ ooda-state-${{ runner.os }}-
33
+
34
+ - name: Install dependencies
35
+ run: npm install
36
+
37
+ - name: Run Linter
38
+ run: npm run lint --if-present
28
39
 
29
40
  - name: Run Unit Tests
30
- run: npm test
41
+ run: npm test --if-present
31
42
 
32
43
  - name: Run Jules PR Self-Audit Gatekeeper
33
- if: matrix.node-version == '20.x' && github.event_name == 'pull_request' && (startsWith(github.actor, 'google-labs-jules') || contains(github.actor, 'jules'))
44
+ if: matrix.node-version == '22.x' && github.event_name == 'pull_request'
34
45
  run: node scripts/jules-self-audit.mjs
35
46
  env:
36
47
  CI: "true"
@@ -99,7 +99,7 @@ Follow all rules strictly.
99
99
  TASK: <description>
100
100
 
101
101
  HARD CONSTRAINTS:
102
- - Do NOT modify package.json, pnpm-lock.yaml, tsconfig.json, astro.config.mjs, wrangler.jsonc, or .github/ files. Enforced in CI by Agent Scope Guard.
102
+ - Do NOT modify package.json, pnpm-lock.yaml, tsconfig.json, or .github/ files. Enforced in CI by Agent Scope Guard.
103
103
  - Diff Payload Governor: Keep total diff payload under 75 KB (`git diff | wc -c`) to prevent API truncation (~80 KB limit).
104
104
  - Verify before finishing: Run full type-check, lint, and unit test suites.
105
105
  - BEFORE opening the PR: Run `git fetch origin main && git rebase origin/main`, then re-verify. If the rebase leaves an empty diff, the work already landed — do NOT submit.
package/README.md CHANGED
@@ -37,14 +37,89 @@ npm run jules:queue
37
37
 
38
38
  ## How It Works
39
39
 
40
- 1. **You Assign Task:** Define what needs fixing or building.
40
+ 1. **You Assign Task:** Define what needs fixing or building (supports text and multimodal image mockups).
41
41
  2. **Jules Writes Code:** Proposes changes in an isolated Git worktree sandbox.
42
42
  3. **Run Tests & Linters:** The Gatekeeper runs your test suite, linters, and type checks.
43
43
  4. **Self-Correction:** If anything fails, Jules automatically retries with fixes (OODA loop).
44
44
  5. **Safe Delivery:** Once tests pass, the PR is verified and ready for review.
45
45
 
46
+ ```mermaid
47
+ sequenceDiagram
48
+ autonumber
49
+
50
+ box "Client Edge" #F4F4F4
51
+ actor Trigger as Client (CLI / CI / SDK)
52
+ end
53
+
54
+ box "Control Plane" #E8F4F8
55
+ participant Orc as Orchestrator Core
56
+ participant Gate as Self-Audit Gatekeeper
57
+ end
58
+
59
+ box "Execution Sandbox" #F8E8E8
60
+ participant API as Google Jules API
61
+ participant Git as Git Worktree Sandbox
62
+ end
63
+
64
+ Trigger->>+Orc: Dispatch Task Payload
65
+
66
+ note over Orc,Git: Phase 1: Security Redaction & Provisioning
67
+ Orc->>Orc: Redact Secrets (Entropy > 3.6) & Enforce Dynamic Guardrails
68
+ Orc->>+Git: Provision Isolation Sandbox (git worktree)
69
+ Git-->>-Orc: Sandbox Ready
70
+
71
+ loop OODA Repair Cycle (Max 3 Retries)
72
+ note over Orc,Git: Phase 2: Agent Execution & Dispatch
73
+ Orc->>+API: Dispatch Task + <MCP_DIRECTIVE> & Target Scope
74
+ API->>+Git: Apply Proposed Code Changes
75
+ Git-->>-API: Changes Written
76
+ API-->>-Orc: Execution Complete
77
+
78
+ note over Orc,Gate: Phase 3: Tiered Verification & Gatekeeping
79
+ Orc->>+Gate: Trigger Self-Audit (trusted origin/main rules)
80
+
81
+ Gate->>+Git: Scope Audit (`git diff -z --name-only` vs forbidden_paths)
82
+ Git-->>-Gate: Diff Stats & File List
83
+
84
+ alt Scope Breach (Forbidden Path OR Diff Payload > 75 KB)
85
+ Gate-->>Orc: Security / Scope Violation Detected
86
+ Orc->>Orc: Record Telemetry (metrics.jsonl)
87
+ Orc-->>Trigger: Abort Execution (Exit 3)
88
+ break Fatal Security Error
89
+ Orc->>Git: Teardown Worktree Sandbox
90
+ end
91
+ else Scope Verification Passed
92
+ Gate->>+Git: Run Dynamic Verification (`testCmd` & `buildCmd`)
93
+ Git-->>-Gate: stdout / stderr verification results
94
+ end
95
+
96
+ alt 100% Verification Suite Passed
97
+ Gate-->>-Orc: Verification Success
98
+ Orc->>+Git: Commit & Push to Remote Branch / PR
99
+ Git-->>-Orc: PR Ready
100
+ Orc->>Orc: Record Telemetry (metrics.jsonl)
101
+ Orc-->>Trigger: Dispatch Succeeded (Exit 0)
102
+ break Task Completed
103
+ Orc->>Git: Teardown Worktree Sandbox
104
+ end
105
+ else Verification Failed
106
+ Gate-->>Orc: Verification Failed (Stderr Trace output)
107
+ Orc->>Orc: Record Failure Telemetry
108
+
109
+ alt Retries Remaining (< 3)
110
+ Orc->>Orc: Construct Repair Prompt with Stderr Trace
111
+ else Max Retries Exceeded (3/3)
112
+ Orc-->>-Trigger: Abort & Log Diagnostic Feedback (Exit 4)
113
+ Orc->>Git: Teardown Worktree Sandbox
114
+ end
115
+ end
116
+ end
117
+ ```
118
+
46
119
  > 💡 **Core Architectural Invariants**:
47
120
  > - **Zero-Trust Base-Branch Security**: Security rules (`forbidden_paths`) are fetched exclusively from `origin/main` (never untrusted PR branches).
121
+ > - **Automatic PII & Secret Redaction**: Outbound task prompts are automatically sanitized to redact API secrets and mask sensitive PII (emails, IPs, phone numbers).
122
+ > - **Ledger Hash-Chain Integrity**: Hashing over JSONL event streams detects unauthorized log tampering or record deletions.
48
123
  > - **Dynamic Command Resolution (`command-resolver.mjs`)**: Auto-detects workspace boundaries (Turborepo, pnpm, Nx, Cargo, pytest, npm).
49
124
  >
50
125
  > 🔍 For a deep dive into the execution protocol, see the [Architecture & Pipeline Flow](docs/architecture.md).
@@ -96,13 +171,16 @@ If no API key is configured, the kit seamlessly falls back to invoking your loca
96
171
  **3. Programmatic Node.js SDK (`index.mjs`)**
97
172
  Downstream Node.js tools, MCP servers, and LLM orchestrators can import kit functions directly:
98
173
  ```js
99
- import { runSelfAudit, scanCodebaseForTodos, resolveProjectCommands } from "jules-orchestrator-kit";
174
+ import { runSelfAudit, dispatchTask, anonymizePii, verifyLedgerIntegrity, validateJulesConfig } from "jules-orchestrator-kit";
175
+
176
+ // Anonymize sensitive PII (emails, IPs, phone numbers) before sending prompts
177
+ const cleanPrompt = anonymizePii("Contact support at john@example.com");
100
178
 
101
- // Run pre-flight sandbox check
102
- await runPreflightSandbox();
179
+ // Programmatically dispatch tasks
180
+ await dispatchTask({ title: "Refactor Auth", prompt: cleanPrompt });
103
181
 
104
- // Scan codebase for TODO/FIXME tasks
105
- const tasks = scanCodebaseForTodos(process.cwd());
182
+ // Verify cryptographic hash chain of event ledgers
183
+ const integrity = verifyLedgerIntegrity(".agent/state/sessions/2026-08-03.jsonl");
106
184
  ```
107
185
 
108
186
  ---
@@ -154,6 +232,7 @@ All commands are registered in `package.json` and can be run via `npm run <comma
154
232
  | `npm run jules:cleanup` | Audits and closes merged or stale REST sessions |
155
233
  | `npm run jules:scan` | Scans the codebase for TODO/FIXME comments and generates a suggested tasks file |
156
234
  | `npm run jules:swarm` | Launches a multi-agent swarm in parallel across isolated worktrees |
235
+ | `npm run jules:merge-swarm` | Autonomous PR merge engine: squash-merges passing, disjoint Jules PRs |
157
236
  | `npm run jules:nightly` | Nightly maintenance job (usually triggered in CI) |
158
237
 
159
238
  ### Environment Variables
@@ -167,7 +246,9 @@ All commands are registered in `package.json` and can be run via `npm run <comma
167
246
  | `JULES_REPOLESS` | Set to `true` or `1` to run in repoless/serverless mode |
168
247
  | `JULES_DRY_RUN` | Set to `true` or `1` to simulate dispatching without making API calls |
169
248
  | `JULES_DAILY_BUDGET` | Daily max session budget for autonomous dispatches (Default: `300`) |
170
- | `JULES_ALLOW_COMMAND_FILE_CHANGES` | Set to `true` to allow PR changes to command-defining files like `package.json` (Default: `false`) |
249
+ | `JULES_MAX_DIFF_KB` | Maximum git diff payload size in KB before aborting with Exit Code 5 (Default: `50`) |
250
+ | `JULES_ALLOW_COMMAND_FILE_CHANGES` | Set to `true` to allow PR changes to command/config files like `package.json`, `tsconfig.json`, `vite.config.ts` (Default: `false`) |
251
+ | `JULES_ALLOW_AGENT_RULE_CHANGES` | Set to `true` to allow PR changes to agent rule files like `AGENTS.md`, `JULES_RULES_TEMPLATE.md` (Default: `false`) |
171
252
  | `BASE_BRANCH` | Base branch for PR Audits & Merge-Base calculations (Default: `main`) |
172
253
  | `GITHUB_HEAD_REF` | PR Head Branch (Used dynamically by CI during OODA repair) |
173
254
  | `JULES_PROJECT_ROOT` | Root directory of the project (Auto-assigned during swarm executions) |
@@ -192,19 +273,19 @@ The Gatekeeper (`jules-self-audit.mjs` and related scripts) uses standard exit c
192
273
  | Code | Meaning | Action Taken |
193
274
  | ---- | ------- | ------------ |
194
275
  | `0` | **Success** | All tests and security checks passed. |
195
- | `1` | **General Error** | Missing dependencies, syntax error, or general failure. |
196
- | `2` | **Setup / Context Error** | Git not found, invalid `BASE_BRANCH`, or trusted base branch extraction failure. |
197
- | `3` | **Security Violation** | Modified file breached `forbidden_paths` or changed command-defining files (`package.json`, `Cargo.toml`). Fails closed immediately. |
198
- | `4` | **Verification Exhausted** | Tests failed and the OODA Auto-Repair loop either exhausted its max retries or is disabled. |
199
- | `5` | **Diff Payload Too Large** | Diff payload size exceeded 75 KB payload governor limit. Split task. |
200
- | `6` | **Secret Leak Prevented** | Secret-like pattern detected in diff. Aborted immediately. |
276
+ | `1` | **Pre-Dispatch / Arg Error** | Missing dependencies, prompt > 50 KB, syntax error, or pre-dispatch failure. |
277
+ | `2` | **API / Network / Quota Error** | REST API HTTP 429 rate limit, HTTP 400 `FAILED_PRECONDITION` quota (~30 active limit), or connection timeout. |
278
+ | `3` | **Security / Scope Violation** | Modified file breached `forbidden_paths` or changed command-defining files (`package.json`, `Cargo.toml`). Fails closed immediately. |
279
+ | `4` | **Verification Exhausted** | Tests failed and the OODA Auto-Repair loop either exhausted its max retries (3) or is disabled. |
280
+ | `5` | **Diff Payload Limit** | Diff payload size exceeded payload governor budget (`JULES_MAX_DIFF_KB`, default 50 KB). Split task. |
281
+ | `6` | **Secret Leak Prevented** | High-confidence secret or private key pattern detected in diff. Aborted immediately. |
201
282
  | `7` | **Budget Exhausted** | Daily session budget limit reached or budget state locked. |
202
283
 
203
284
  ---
204
285
 
205
286
  ## Contributing
206
287
  We welcome contributions! Please follow these core principles:
207
- 1. **Zero External Dependencies**: Use ONLY native Node.js built-in modules (`node:fs`, `node:path`, `node:child_process`, `node:crypto`, `node:util`).
288
+ 1. **Zero Runtime Dependencies**: Use ONLY native Node.js built-in modules (`node:fs`, `node:path`, `node:child_process`, `node:crypto`, `node:util`).
208
289
  2. **Verification Suite**: Ensure 100% of unit tests pass cleanly (`npm test`).
209
290
  3. **Conventional Commits**: Use standardized prefixes (`feat:`, `fix:`, `docs:`, `test:`, `chore:`).
210
291
  4. **Cross-Platform Compatibility**: Normalize Windows backslashes (`\`) to POSIX slashes (`/`) for glob patterns and paths.
package/bin/init.js CHANGED
@@ -157,7 +157,7 @@ if (!fs.existsSync(yamlConfigPath) || isForce) {
157
157
  version: 2
158
158
  test_cmd: "${detected.testCmd || "npm test"}"
159
159
  build_cmd: "${detected.buildCmd || "npm run build"}"
160
- forbidden_paths: [".github/**", "**/secrets/**", "**/*.pem", "**/lock-manager/**"]
160
+ forbidden_paths: [".github/**", "**/.env*", "**/*.pem", "**/lock-manager*"]
161
161
  `;
162
162
  fs.writeFileSync(yamlConfigPath, yamlContent, "utf-8");
163
163
  console.log("✅ Created: .agent/jules.yml");
@@ -265,6 +265,9 @@ const requiredGitignoreEntries = [
265
265
  ".env",
266
266
  ".agent/history/",
267
267
  ".agent/state/",
268
+ ".agent/jules-queue/.state/",
269
+ ".agent/jules-queue/failed/",
270
+ ".agent/jules-queue/.processing/",
268
271
  ".agent/jules-queue/*.md",
269
272
  "!.agent/jules-queue/README.md"
270
273
  ];
package/index.mjs CHANGED
@@ -1,11 +1,12 @@
1
1
  /**
2
2
  * jules-orchestrator-kit Node.js SDK
3
3
  * Primary entrypoint for programmatically orchestrating Google Jules workflows.
4
- * Zero external dependencies.
4
+ * Zero runtime dependencies.
5
5
  */
6
6
 
7
7
  export { resolveProjectCommands, resolveWorkspaceExecutionBoundary } from "./scripts/command-resolver.mjs";
8
- export { runSelfAudit, runPreflightSandbox, loadForbiddenPatterns, loadAllowedPatterns, matchGlob } from "./scripts/jules-self-audit.mjs";
8
+ export { runSelfAudit, runPreflightSandbox, loadForbiddenPatterns, loadAllowedPatterns, matchGlob, validateJulesConfig } from "./scripts/jules-self-audit.mjs";
9
9
  export { scanCodebaseForTodos, runScanner } from "./scripts/jules-scan-todos.mjs";
10
- export { log, logToHistory, ensureDir, resolveMarkdownConflict, redactSecrets } from "./scripts/utils.mjs";
11
- export { getDynamicGuardrails } from "./scripts/jules-dispatch.mjs";
10
+ export { log, logToHistory, ensureDir, resolveMarkdownConflict, redactSecrets, anonymizePii, verifyLedgerIntegrity, loadEnv } from "./scripts/utils.mjs";
11
+ export { getDynamicGuardrails, dispatchTask } from "./scripts/jules-dispatch.mjs";
12
+ export { classifyQueueFailure } from "./scripts/jules-queue-runner.mjs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jules-orchestrator-kit",
3
- "version": "0.8.0",
3
+ "version": "0.8.5",
4
4
  "description": "Orchestration kit for running Google Jules autonomous agents.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,7 +27,7 @@
27
27
  ".agent/rules/",
28
28
  ".agent/workflows/",
29
29
  ".agent/jules-queue/README.md",
30
- ".github/",
30
+ ".github/workflows/jules-audit.yml",
31
31
  ".env.example",
32
32
  "JULES_RULES_TEMPLATE.md",
33
33
  "README.md",
@@ -35,7 +35,7 @@
35
35
  ],
36
36
  "scripts": {
37
37
  "init": "node bin/init.js",
38
- "test": "node --test test/kit.test.mjs",
38
+ "test": "node --test test/*.test.mjs",
39
39
  "jules:dispatch": "node scripts/jules-dispatch.mjs",
40
40
  "jules:queue": "node scripts/jules-queue-runner.mjs",
41
41
  "jules:create": "node scripts/jules-create.mjs",
@@ -44,7 +44,10 @@
44
44
  "jules:cleanup": "node scripts/jules-cleanup.mjs",
45
45
  "jules:scan": "node scripts/jules-scan-todos.mjs",
46
46
  "jules:swarm": "node scripts/jules-swarm.mjs",
47
- "jules:nightly": "node scripts/jules-nightly.mjs"
47
+ "jules:merge-swarm": "node scripts/jules-merge-swarm.mjs",
48
+ "jules:patch": "node scripts/jules-patch.mjs",
49
+ "jules:nightly": "node scripts/jules-nightly.mjs",
50
+ "lint": "eslint ."
48
51
  },
49
52
  "engines": {
50
53
  "node": ">=18.0.0"
@@ -58,5 +61,9 @@
58
61
  "automation"
59
62
  ],
60
63
  "author": "FullThrottle83",
61
- "license": "MIT"
64
+ "license": "MIT",
65
+ "devDependencies": {
66
+ "eslint": "^9.39.5",
67
+ "globals": "^17.8.0"
68
+ }
62
69
  }
@@ -1,6 +1,23 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
 
4
+ export function detectPackageManager(root = process.cwd(), pkg = {}) {
5
+ if (fs.existsSync(path.join(root, "pnpm-lock.yaml"))) return "pnpm";
6
+ if (fs.existsSync(path.join(root, "yarn.lock"))) return "yarn";
7
+ if (fs.existsSync(path.join(root, "bun.lockb"))) return "bun";
8
+ if (fs.existsSync(path.join(root, "package-lock.json"))) return "npm";
9
+
10
+ const pm = pkg.packageManager;
11
+ if (typeof pm === "string") {
12
+ if (pm.startsWith("pnpm")) return "pnpm";
13
+ if (pm.startsWith("yarn")) return "yarn";
14
+ if (pm.startsWith("bun")) return "bun";
15
+ if (pm.startsWith("npm")) return "npm";
16
+ }
17
+
18
+ return "npm";
19
+ }
20
+
4
21
  /**
5
22
  * Dynamic Framework-Agnostic Command Resolver
6
23
  * Sniffs project manifests to return proper build & test verification commands.
@@ -44,23 +61,6 @@ export function resolveProjectCommands(projectRoot = process.cwd()) {
44
61
  }
45
62
  }
46
63
 
47
- function detectPackageManager(root, pkg = {}) {
48
- if (fs.existsSync(path.join(root, "pnpm-lock.yaml"))) return "pnpm";
49
- if (fs.existsSync(path.join(root, "yarn.lock"))) return "yarn";
50
- if (fs.existsSync(path.join(root, "bun.lockb"))) return "bun";
51
- if (fs.existsSync(path.join(root, "package-lock.json"))) return "npm";
52
-
53
- const pm = pkg.packageManager;
54
- if (typeof pm === "string") {
55
- if (pm.startsWith("pnpm")) return "pnpm";
56
- if (pm.startsWith("yarn")) return "yarn";
57
- if (pm.startsWith("bun")) return "bun";
58
- if (pm.startsWith("npm")) return "npm";
59
- }
60
-
61
- return "npm";
62
- }
63
-
64
64
  // 2. Dynamic Detector Strategy List
65
65
  const detectors = [
66
66
  {
@@ -3,36 +3,19 @@
3
3
  * Jules Session Cleanup & PR Audit Utility
4
4
  * Cross-references active/completed Jules REST API sessions with GitHub PR merge status
5
5
  * to report and safely close merged or stale sessions.
6
- * Zero external dependencies.
6
+ * Zero runtime dependencies.
7
7
  */
8
8
 
9
9
  import { execFileSync } from "node:child_process";
10
- import fs from "node:fs";
11
10
  import path from "node:path";
12
- import { log } from "./utils.mjs";
13
-
14
- function loadEnv() {
15
- const envPath = path.resolve(process.cwd(), ".env");
16
- if (fs.existsSync(envPath)) {
17
- const lines = fs.readFileSync(envPath, "utf-8").split("\n");
18
- for (const line of lines) {
19
- const trimmed = line.trim();
20
- if (!trimmed || trimmed.startsWith("#")) continue;
21
- const eqIdx = trimmed.indexOf("=");
22
- if (eqIdx > 0) {
23
- const key = trimmed.slice(0, eqIdx).trim().replace(/^export\s+/, "");
24
- let val = trimmed.slice(eqIdx + 1).trim();
25
- if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
26
- val = val.slice(1, -1);
27
- }
28
- if (!process.env[key]) {
29
- process.env[key] = val;
30
- }
31
- }
32
- }
33
- }
11
+ import { fileURLToPath } from "node:url";
12
+ import { log, loadEnv } from "./utils.mjs";
13
+
14
+ const isMainModule = process.argv[1] && path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url));
15
+
16
+ if (isMainModule) {
17
+ loadEnv();
34
18
  }
35
- loadEnv();
36
19
 
37
20
  const args = process.argv.slice(2);
38
21
  const isDryRun = args.includes("--dry-run") || process.env.JULES_DRY_RUN === "true" || process.env.JULES_DRY_RUN === "1";
@@ -198,3 +181,10 @@ export async function runCleanup() {
198
181
  }
199
182
  }
200
183
  }
184
+
185
+ if (isMainModule) {
186
+ runCleanup().catch((err) => {
187
+ log.error(`Cleanup audit failed: ${err.message}`);
188
+ process.exit(1);
189
+ });
190
+ }
@@ -6,14 +6,18 @@
6
6
 
7
7
  import fs from "node:fs";
8
8
  import path from "node:path";
9
+ import { fileURLToPath } from "node:url";
9
10
  import { log, ensureDir } from "./utils.mjs";
10
11
 
11
- const taskTitle = process.argv[2];
12
+ const isMainModule = process.argv[1] && path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url));
12
13
 
13
- if (!taskTitle) {
14
- log.error("Usage: npm run jules:create \"Task Title\"");
15
- process.exit(1);
16
- }
14
+ if (isMainModule) {
15
+ const taskTitle = process.argv[2];
16
+
17
+ if (!taskTitle) {
18
+ log.error("Usage: npm run jules:create \"Task Title\"");
19
+ process.exit(1);
20
+ }
17
21
 
18
22
  const queueDir = path.resolve(process.cwd(), ".agent/jules-queue");
19
23
  ensureDir(queueDir);
@@ -65,3 +69,4 @@ try {
65
69
  log.error(`Failed to create task file: ${err.message}`);
66
70
  process.exit(1);
67
71
  }
72
+ }