jules-orchestrator-kit 0.7.0 → 0.8.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jules-orchestrator-kit",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Orchestration kit for running Google Jules autonomous agents.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -44,6 +44,23 @@ export function resolveProjectCommands(projectRoot = process.cwd()) {
44
44
  }
45
45
  }
46
46
 
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
+
47
64
  // 2. Dynamic Detector Strategy List
48
65
  const detectors = [
49
66
  {
@@ -59,20 +76,21 @@ export function resolveProjectCommands(projectRoot = process.cwd()) {
59
76
  resolve: (root) => {
60
77
  try {
61
78
  const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf-8"));
79
+ const pm = detectPackageManager(root, pkg);
62
80
  const scripts = pkg.scripts || {};
63
- let verifyScript = scripts["check:all"] ? "npm run check:all" : "";
81
+ let verifyScript = scripts["check:all"] ? `${pm} run check:all` : "";
64
82
  if (!verifyScript) {
65
83
  const parts = [];
66
- if (scripts.lint) parts.push("npm run lint");
67
- else if (scripts.check) parts.push("npm run check");
68
- if (scripts.test) parts.push("npm test");
84
+ if (scripts.lint) parts.push(`${pm} run lint`);
85
+ else if (scripts.check) parts.push(`${pm} run check`);
86
+ if (scripts.test) parts.push(`${pm} test`);
69
87
  verifyScript = parts.join(" && ");
70
88
  }
71
- const buildScript = scripts.build ? "npm run build" : "";
89
+ const buildScript = scripts.build ? `${pm} run build` : "";
72
90
  return {
73
- testCmd: verifyScript || "npm test",
91
+ testCmd: verifyScript || `${pm} test`,
74
92
  buildCmd: buildScript,
75
- source: "package.json",
93
+ source: `package.json (${pm})`,
76
94
  };
77
95
  } catch (err) {
78
96
  console.warn("⚠️ Failed to parse package.json:", err.message);
@@ -1,17 +1,18 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Jules Task Status Utility
4
- * Parses the queue.jsonl file and renders a clean console.table
5
- */
6
-
7
1
  import fs from "node:fs";
8
2
  import path from "node:path";
9
- import { log } from "./utils.mjs";
3
+ import { log, checkDailyBudget } from "./utils.mjs";
10
4
 
5
+ const isJson = process.argv.includes("--json");
11
6
  const queueLogPath = path.resolve(process.cwd(), ".agent/jules-queue/queue.jsonl");
12
7
 
8
+ const budgetInfo = checkDailyBudget();
9
+
13
10
  if (!fs.existsSync(queueLogPath)) {
14
- log.info("Queue log is empty. No tasks have been dispatched yet.");
11
+ if (isJson) {
12
+ console.log(JSON.stringify({ queue: [], budget: budgetInfo }, null, 2));
13
+ } else {
14
+ log.info("Queue log is empty. No tasks have been dispatched yet.");
15
+ }
15
16
  process.exit(0);
16
17
  }
17
18
 
@@ -20,7 +21,11 @@ try {
20
21
  const lines = content.split("\n").filter(Boolean);
21
22
 
22
23
  if (lines.length === 0) {
23
- log.info("Queue log is empty.");
24
+ if (isJson) {
25
+ console.log(JSON.stringify({ queue: [], budget: budgetInfo }, null, 2));
26
+ } else {
27
+ log.info("Queue log is empty.");
28
+ }
24
29
  process.exit(0);
25
30
  }
26
31
 
@@ -32,10 +37,11 @@ try {
32
37
  const entry = JSON.parse(line);
33
38
  if (entry.file) {
34
39
  statusMap.set(entry.file, {
40
+ file: entry.file,
35
41
  Task: entry.file.replace(/^TASK-\d+-/, "").replace(/\.md$/, ""),
36
42
  Status: entry.status,
37
- Timestamp: new Date(entry.timestamp).toLocaleString(),
38
- Error: entry.error || "-"
43
+ Timestamp: entry.timestamp,
44
+ Error: entry.error || null
39
45
  });
40
46
  }
41
47
  } catch (e) {
@@ -43,15 +49,26 @@ try {
43
49
  }
44
50
  }
45
51
 
46
- if (statusMap.size === 0) {
52
+ const tasksList = Array.from(statusMap.values());
53
+
54
+ if (isJson) {
55
+ console.log(JSON.stringify({ queue: tasksList, budget: budgetInfo }, null, 2));
56
+ process.exit(0);
57
+ }
58
+
59
+ if (tasksList.length === 0) {
47
60
  log.info("No parseable task events found in queue.jsonl");
48
61
  process.exit(0);
49
62
  }
50
63
 
51
- log.header("Jules Queue Status");
52
- console.table(Array.from(statusMap.values()));
64
+ log.header(`JULES QUEUE STATUS (Budget: ${budgetInfo.used}/${budgetInfo.budget} sessions used)`);
65
+ console.table(tasksList.map(t => ({ Task: t.Task, Status: t.Status, Timestamp: new Date(t.Timestamp).toLocaleString(), Error: t.Error || "-" })));
53
66
 
54
67
  } catch (err) {
55
- log.error(`Failed to read queue log: ${err.message}`);
68
+ if (isJson) {
69
+ console.log(JSON.stringify({ error: err.message }, null, 2));
70
+ } else {
71
+ log.error(`Failed to read queue log: ${err.message}`);
72
+ }
56
73
  process.exit(1);
57
74
  }
@@ -194,8 +194,8 @@ async function runSwarm() {
194
194
  env: {
195
195
  ...process.env,
196
196
  JULES_PROJECT_ROOT: process.env.JULES_PROJECT_ROOT,
197
- JULES_SLOT_INDEX: String(bIdx + 1),
198
- JULES_SLOT_TOTAL: String(batch.length)
197
+ JULES_SLOT_INDEX: String(taskNum),
198
+ JULES_SLOT_TOTAL: String(tasks.length)
199
199
  },
200
200
  });
201
201
  if (stdout) log.dim(stdout.trim());
package/scripts/utils.mjs CHANGED
@@ -165,10 +165,15 @@ export function redactSecrets(text) {
165
165
  return sanitized;
166
166
  }
167
167
 
168
- export function appendLedger(ledgerName, payload) {
169
- const stateDir = path.resolve(process.env.JULES_PROJECT_ROOT || process.cwd(), ".agent/state");
168
+ export function getDailyLedgerPath(ledgerName = "sessions") {
169
+ const dateStr = new Date().toISOString().split("T")[0];
170
+ const stateDir = path.resolve(process.env.JULES_PROJECT_ROOT || process.cwd(), ".agent/state", ledgerName);
170
171
  ensureDir(stateDir);
171
- const ledgerPath = path.join(stateDir, `${ledgerName}.jsonl`);
172
+ return path.join(stateDir, `${dateStr}.jsonl`);
173
+ }
174
+
175
+ export function appendLedger(ledgerName, payload) {
176
+ const ledgerPath = getDailyLedgerPath(ledgerName);
172
177
  const entry = JSON.stringify({
173
178
  timestamp: new Date().toISOString(),
174
179
  ...payload
@@ -179,33 +184,30 @@ export function appendLedger(ledgerName, payload) {
179
184
 
180
185
  export function checkDailyBudget(maxSessions = 300) {
181
186
  const dateStr = new Date().toISOString().split("T")[0];
182
- const stateDir = path.resolve(process.env.JULES_PROJECT_ROOT || process.cwd(), ".agent/state");
183
- const sessionsLedger = path.join(stateDir, "sessions.jsonl");
187
+ const ledgerPath = getDailyLedgerPath("sessions");
184
188
 
185
- if (!fs.existsSync(sessionsLedger)) {
189
+ if (!fs.existsSync(ledgerPath)) {
186
190
  return { ok: true, used: 0, budget: maxSessions };
187
191
  }
188
192
 
189
- const content = fs.readFileSync(sessionsLedger, "utf-8");
193
+ const content = fs.readFileSync(ledgerPath, "utf-8");
190
194
  const lines = content.split("\n").filter(Boolean);
191
195
 
192
196
  let usedToday = 0;
193
197
  for (const line of lines) {
194
198
  try {
195
199
  const entry = JSON.parse(line);
196
- if (
197
- entry.timestamp &&
198
- entry.timestamp.startsWith(dateStr) &&
199
- (entry.event === "budget_reserved" || !entry.event)
200
- ) {
200
+ if (entry.event === "budget_reserved" || !entry.event) {
201
201
  usedToday++;
202
202
  }
203
- } catch (e) {
204
- // Ignore
205
- }
203
+ } catch (_) {}
206
204
  }
207
205
 
208
- return { ok: usedToday < maxSessions, used: usedToday, budget: maxSessions };
206
+ return {
207
+ ok: usedToday < maxSessions,
208
+ used: usedToday,
209
+ budget: maxSessions
210
+ };
209
211
  }
210
212
 
211
213
  function sleepSync(ms) {