jules-orchestrator-kit 0.8.5 → 0.9.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.
Files changed (41) hide show
  1. package/.agent/jules-queue/README.md +4 -4
  2. package/.agent/prompts/Bolt.md +18 -0
  3. package/.agent/prompts/Overseer.md +18 -0
  4. package/.agent/prompts/Sentinel.md +18 -0
  5. package/.agent/prompts/Task_Template.md +26 -0
  6. package/JULES_RULES_TEMPLATE.md +6 -1
  7. package/README.md +25 -13
  8. package/bin/agentctl.mjs +274 -0
  9. package/index.mjs +32 -5
  10. package/package.json +11 -2
  11. package/scripts/asset-integrity-check.mjs +35 -0
  12. package/scripts/command-resolver.mjs +37 -214
  13. package/scripts/jules-cleanup.mjs +23 -164
  14. package/scripts/jules-create.mjs +12 -56
  15. package/scripts/jules-dispatch.mjs +103 -449
  16. package/scripts/jules-merge-swarm.mjs +19 -173
  17. package/scripts/jules-nightly.mjs +7 -128
  18. package/scripts/jules-patch.mjs +15 -103
  19. package/scripts/jules-queue-runner.mjs +28 -221
  20. package/scripts/jules-scan-todos.mjs +31 -125
  21. package/scripts/jules-self-audit.mjs +69 -656
  22. package/scripts/jules-status.mjs +42 -70
  23. package/scripts/jules-swarm.mjs +23 -327
  24. package/scripts/jules-webhook-receiver.mjs +70 -0
  25. package/scripts/lock-manager.mjs +11 -177
  26. package/scripts/risk-tier.mjs +29 -0
  27. package/scripts/rules-lint.mjs +20 -0
  28. package/scripts/stale-base-check.mjs +26 -0
  29. package/scripts/utils.mjs +107 -369
  30. package/scripts/validate-envelope.mjs +44 -0
  31. package/src/asset_integrity.mjs +76 -0
  32. package/src/config.mjs +325 -0
  33. package/src/engine.mjs +217 -0
  34. package/src/envelope.mjs +105 -0
  35. package/src/git.mjs +127 -0
  36. package/src/provider.mjs +179 -0
  37. package/src/risk.mjs +120 -0
  38. package/src/rules_budget.mjs +77 -0
  39. package/src/security.mjs +212 -0
  40. package/src/state.mjs +209 -0
  41. package/src/webhook.mjs +138 -0
@@ -1,188 +1,22 @@
1
- #!/usr/bin/env node
2
-
3
1
  /**
4
- * lock-manager.mjs
5
- *
6
- * Manages multi-agent file locks to prevent concurrent modification collisions.
7
- * Uses .agent/sync-manifest.json as the lock registry.
8
- *
9
- * Usage:
10
- * node scripts/lock-manager.mjs acquire <agent_name> <task_id> <file_path1> <file_path2> [--unattended]
11
- * node scripts/lock-manager.mjs release <task_id>
2
+ * Backward compatibility shim for lock-manager.mjs in v0.9.0.
3
+ * Delegates to src/state.mjs.
12
4
  */
13
5
 
14
- import fs from 'node:fs/promises';
15
- import path from 'node:path';
16
- import { fileURLToPath } from 'node:url';
17
-
18
- const MANIFEST_PATH = path.join(process.cwd(), '.agent', 'file-locks.json');
19
- const TTL_MS = 20 * 60 * 1000; // 20 minutes
20
- const isMainModule = process.argv[1] && path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url));
6
+ import { acquireLock, releaseLock, lockStatus } from "../src/state.mjs";
21
7
 
22
- async function readManifest() {
23
- try {
24
- const data = await fs.readFile(MANIFEST_PATH, 'utf-8');
25
- return JSON.parse(data);
26
- } catch (err) {
27
- if (err.code === 'ENOENT') {
28
- return {};
29
- }
30
- throw err;
31
- }
8
+ export function acquire(agent, taskId, filePaths = [], opts = {}) {
9
+ return acquireLock(agent, taskId, filePaths, opts);
32
10
  }
33
11
 
34
- async function writeManifest(manifest) {
35
- await fs.mkdir(path.dirname(MANIFEST_PATH), { recursive: true });
36
- const tmp = MANIFEST_PATH + `.tmp-${process.pid}`;
37
- await fs.writeFile(tmp, JSON.stringify(manifest, null, 2), 'utf-8');
38
- await fs.rename(tmp, MANIFEST_PATH);
39
- }
40
-
41
- async function withManifestLock(fn) {
42
- const lockPath = MANIFEST_PATH + ".lock";
43
- await fs.mkdir(path.dirname(lockPath), { recursive: true });
44
- for (let i = 0; i < 50; i++) {
45
- try {
46
- const stats = await fs.stat(lockPath);
47
- if (Date.now() - stats.mtimeMs > 5 * 60 * 1000) {
48
- await fs.rm(lockPath, { force: true });
49
- }
50
- } catch (_) {}
51
-
52
- let handle;
53
- try {
54
- handle = await fs.open(lockPath, "wx");
55
- } catch (err) {
56
- if (err.code !== "EEXIST") throw err;
57
- await new Promise(r => setTimeout(r, 50 + Math.random() * 50));
58
- continue;
59
- }
60
- try { return await fn(); }
61
- finally {
62
- try { await handle.close(); } catch (_) {}
63
- await fs.rm(lockPath, { force: true });
64
- }
65
- }
66
- throw new Error("Could not acquire manifest lock");
12
+ export function release(agent, taskId, opts = {}) {
13
+ return releaseLock(agent, taskId, opts);
67
14
  }
68
15
 
69
- function cleanExpiredLocks(manifest) {
70
- const now = Date.now();
71
- let changed = false;
72
- for (const [file, lock] of Object.entries(manifest)) {
73
- if (lock.expiresAt < now) {
74
- delete manifest[file];
75
- changed = true;
76
- }
77
- }
78
- return changed;
79
- }
80
-
81
- async function acquireLocks(agentName, taskId, files, isUnattended = false) {
82
- await withManifestLock(async () => {
83
- if (isUnattended) {
84
- console.log(`[lock-manager] Operating in unattended mode for task ${taskId}`);
85
- }
86
- const manifest = await readManifest();
87
- cleanExpiredLocks(manifest);
88
-
89
- const now = Date.now();
90
- const expiresAt = now + TTL_MS;
91
-
92
- const conflicts = [];
93
- for (const file of files) {
94
- const normalizedFile = path.normalize(file);
95
- if (manifest[normalizedFile] && manifest[normalizedFile].taskId !== taskId) {
96
- conflicts.push({
97
- file: normalizedFile,
98
- lockedBy: manifest[normalizedFile].agentName,
99
- task: manifest[normalizedFile].taskId
100
- });
101
- }
102
- }
103
-
104
- if (conflicts.length > 0) {
105
- let msg = `Cannot acquire locks for task ${taskId}. Conflicts detected:\n`;
106
- for (const conflict of conflicts) {
107
- msg += ` - ${conflict.file} is locked by ${conflict.lockedBy} (Task: ${conflict.task})\n`;
108
- }
109
- throw new Error(msg.trim());
110
- }
111
-
112
- for (const file of files) {
113
- const normalizedFile = path.normalize(file);
114
- manifest[normalizedFile] = {
115
- agentName,
116
- taskId,
117
- acquiredAt: now,
118
- expiresAt
119
- };
120
- }
121
-
122
- await writeManifest(manifest);
123
- console.log(`SUCCESS: Acquired locks for task ${taskId} on ${files.length} files.`);
124
- });
125
- }
126
-
127
- async function releaseLocks(taskId) {
128
- await withManifestLock(async () => {
129
- const manifest = await readManifest();
130
- let releasedCount = 0;
131
-
132
- for (const [file, lock] of Object.entries(manifest)) {
133
- if (lock.taskId === taskId) {
134
- delete manifest[file];
135
- releasedCount++;
136
- }
137
- }
138
-
139
- if (releasedCount > 0) {
140
- await writeManifest(manifest);
141
- console.log(`SUCCESS: Released ${releasedCount} locks for task ${taskId}.`);
142
- } else {
143
- console.log(`INFO: No locks found for task ${taskId}.`);
144
- }
145
- });
146
- }
147
-
148
- async function main() {
149
- const args = process.argv.slice(2);
150
- const command = args[0];
151
-
152
- if (command === 'acquire') {
153
- const agentName = args[1];
154
- const taskId = args[2];
155
- const unattendedIndex = args.indexOf('--unattended');
156
- const isUnattended = unattendedIndex !== -1;
157
- let files = [];
158
- if (isUnattended) {
159
- files = args.slice(3, unattendedIndex).concat(args.slice(unattendedIndex + 1));
160
- } else {
161
- files = args.slice(3);
162
- }
163
-
164
- if (!agentName || !taskId || files.length === 0) {
165
- console.error('Usage: acquire <agent_name> <task_id> <file_paths...> [--unattended]');
166
- process.exit(1);
167
- }
168
-
169
- await acquireLocks(agentName, taskId, files, isUnattended);
170
- } else if (command === 'release') {
171
- const taskId = args[1];
172
- if (!taskId) {
173
- console.error('Usage: release <task_id>');
174
- process.exit(1);
175
- }
176
- await releaseLocks(taskId);
177
- } else {
178
- console.error('Unknown command. Use "acquire" or "release".');
179
- process.exit(1);
180
- }
16
+ export function status(opts = {}) {
17
+ return lockStatus(opts);
181
18
  }
182
19
 
183
- if (isMainModule) {
184
- main().catch(err => {
185
- console.error('Unhandled error:', err);
186
- process.exit(1);
187
- });
20
+ export function cleanup() {
21
+ return { removed: 0 };
188
22
  }
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { changedFiles } from "../src/git.mjs";
4
+ import { classifyRiskTier } from "../src/risk.mjs";
5
+
6
+ const root = process.cwd();
7
+ const baseBranch = process.env.BASE_BRANCH || "main";
8
+
9
+ try {
10
+ const files = changedFiles(root, baseBranch);
11
+ const result = classifyRiskTier(files);
12
+
13
+ console.log(`[risk-tier] Classified PR Risk Tier: ${result.tier}`);
14
+ console.log(`[risk-tier] Reason: ${result.reason}`);
15
+ console.log(`[risk-tier] Auto-Merge Allowed: ${result.isAutoMergeAllowed}`);
16
+ console.log(`[risk-tier] Requires Human Review: ${result.requiresHumanReview}`);
17
+
18
+ if (process.env.GITHUB_OUTPUT) {
19
+ const { appendFileSync } = await import("node:fs");
20
+ appendFileSync(process.env.GITHUB_OUTPUT, `risk_tier=${result.tier}\n`);
21
+ appendFileSync(process.env.GITHUB_OUTPUT, `auto_merge=${result.isAutoMergeAllowed}\n`);
22
+ appendFileSync(process.env.GITHUB_OUTPUT, `requires_human=${result.requiresHumanReview}\n`);
23
+ }
24
+
25
+ process.exit(0);
26
+ } catch (err) {
27
+ console.error(`❌ Risk tier classification failed: ${err.message}`);
28
+ process.exit(1);
29
+ }
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { checkRulesBudget } from "../src/rules_budget.mjs";
4
+
5
+ const root = process.cwd();
6
+ const res = checkRulesBudget(root);
7
+
8
+ console.log("[rules-lint] Auditing character and line budgets for agent rule files...");
9
+
10
+ if (!res.ok) {
11
+ console.error("❌ RULES BUDGET VIOLATIONS DETECTED:");
12
+ for (const v of res.violations) {
13
+ console.error(` - ${v.path}: ${v.reason}`);
14
+ }
15
+ console.error("\nRemediation: Trim prose rules or convert textual learnings into AST lints / Vitest assertions.");
16
+ process.exit(1);
17
+ }
18
+
19
+ console.log("✅ All agent rule files are within safe character (<10,000) and line (<250) budget limits.");
20
+ process.exit(0);
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { git, resolveBase } from "../src/git.mjs";
4
+
5
+ const root = process.cwd();
6
+ const maxBehind = parseInt(process.env.STALE_BASE_MAX_COMMITS || "25", 10);
7
+ const baseBranch = process.env.BASE_BRANCH || "main";
8
+
9
+ try {
10
+ const resolvedBase = resolveBase(root, baseBranch);
11
+ const behindStr = git(["rev-list", "--count", `${resolvedBase}..HEAD`], { cwd: root, ignoreError: true });
12
+ const behindCount = parseInt(behindStr || "0", 10);
13
+
14
+ console.log(`[stale-base-check] Branch HEAD is ${behindCount} commits behind ${resolvedBase} (max allowed: ${maxBehind}).`);
15
+
16
+ if (!isNaN(behindCount) && behindCount > maxBehind) {
17
+ console.error(`❌ STALE BASE GATE FAIL: PR branch is ${behindCount} commits behind ${resolvedBase}. Rebase onto latest ${baseBranch} before merging.`);
18
+ process.exit(1);
19
+ }
20
+
21
+ console.log("✅ Stale-base predicate check passed.");
22
+ process.exit(0);
23
+ } catch (err) {
24
+ console.warn(`⚠️ Stale-base check skipped (git base ref not available or shallow clone): ${err.message}`);
25
+ process.exit(0);
26
+ }