jules-orchestrator-kit 0.9.3 → 0.9.4

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
@@ -58,6 +58,7 @@ sequenceDiagram
58
58
 
59
59
  box "Control Plane" #E8F4F8
60
60
  participant Orc as Orchestrator Core
61
+ participant Envelope as Task Envelope Validator
61
62
  participant Gate as Self-Audit Gatekeeper
62
63
  end
63
64
 
@@ -66,12 +67,19 @@ sequenceDiagram
66
67
  participant Git as Git Worktree Sandbox
67
68
  end
68
69
 
69
- Trigger->>+Orc: Dispatch Task Payload
70
+ Trigger->>+Orc: Dispatch Task Payload / Envelope
70
71
 
71
- note over Orc,Git: Phase 1: Security Redaction & Provisioning
72
- Orc->>Orc: Redact Secrets (Entropy > 3.6) & Enforce Dynamic Guardrails
73
- Orc->>+Git: Provision Isolation Sandbox (git worktree)
74
- Git-->>-Orc: Sandbox Ready
72
+ note over Orc,Envelope: Phase 1: Pre-Flight Premise & Security Validation
73
+ Orc->>+Envelope: Validate Envelope (referenced_paths exist? base commit fresh?)
74
+ alt Premise Failure / Missing Referenced Paths / Stale Base
75
+ Envelope-->>Orc: Validation Failed (Premise Error)
76
+ Orc-->>Trigger: Abort Pre-Dispatch (Exit 1)
77
+ else Envelope Validated
78
+ Envelope-->>-Orc: Envelope Approved
79
+ Orc->>Orc: Redact Secrets (Entropy > 3.6) & Enforce Dynamic Guardrails
80
+ Orc->>+Git: Provision Isolation Sandbox (git worktree)
81
+ Git-->>-Orc: Sandbox Ready
82
+ end
75
83
 
76
84
  loop OODA Repair Cycle (Max 3 Retries)
77
85
  note over Orc,Git: Phase 2: Agent Execution & Dispatch
@@ -80,28 +88,29 @@ sequenceDiagram
80
88
  Git-->>-API: Changes Written
81
89
  API-->>-Orc: Execution Complete
82
90
 
83
- note over Orc,Gate: Phase 3: Tiered Verification & Gatekeeping
91
+ note over Orc,Gate: Phase 3: Multi-Gate Verification & Risk Classification
84
92
  Orc->>+Gate: Trigger Self-Audit (trusted origin/main rules)
85
93
 
86
- Gate->>+Git: Scope Audit (`git diff -z --name-only` vs forbidden_paths)
87
- Git-->>-Gate: Diff Stats & File List
94
+ Gate->>+Git: Run Scope, Payload & Stale-Base Audit (`git diff`)
95
+ Git-->>-Gate: Diff Stats & Base Commit Age
88
96
 
89
- alt Scope Breach (Forbidden Path OR Diff Payload > 75 KB)
90
- Gate-->>Orc: Security / Scope Violation Detected
97
+ alt Scope Breach / Payload > 75 KB / Stale Base > 25 commits
98
+ Gate-->>Orc: Security / Scope / Stale-Base Violation
91
99
  Orc->>Orc: Record Telemetry (metrics.jsonl)
92
100
  Orc-->>Trigger: Abort Execution (Exit 3)
93
- break Fatal Security Error
101
+ break Fatal Security or Base Error
94
102
  Orc->>Git: Teardown Worktree Sandbox
95
103
  end
96
- else Scope Verification Passed
97
- Gate->>+Git: Run Dynamic Verification (`testCmd` & `buildCmd`)
98
- Git-->>-Gate: stdout / stderr verification results
104
+ else Static Scope & Base Passed
105
+ Gate->>Gate: Classify Risk Tier (R0 Cosmetic, R1 Routine, R2 Consequential, R3 Restricted)
106
+ Gate->>+Git: Run Integrity Checks (Asset Magic-Bytes, Rules Budget, testCmd & buildCmd)
107
+ Git-->>-Gate: Execution & Integrity Proof (stdout/stderr)
99
108
  end
100
109
 
101
- alt 100% Verification Suite Passed
102
- Gate-->>-Orc: Verification Success
110
+ alt 100% Verification Suite & Integrity Passed
111
+ Gate-->>-Orc: Verification Success + Risk Tier Metadata
103
112
  Orc->>+Git: Commit & Push to Remote Branch / PR
104
- Git-->>-Orc: PR Ready
113
+ Git-->>-Orc: PR Ready (Attached Execution Receipts)
105
114
  Orc->>Orc: Record Telemetry (metrics.jsonl)
106
115
  Orc-->>Trigger: Dispatch Succeeded (Exit 0)
107
116
  break Task Completed
@@ -122,10 +131,12 @@ sequenceDiagram
122
131
  ```
123
132
 
124
133
  > 💡 **Core Architectural Invariants**:
134
+ > - **Task Envelope Premise Validation**: Pre-flight checks verify referenced paths and base freshness before dispatching tasks to prevent session burnout.
135
+ > - **Risk Tier Classification Engine (R0–R3)**: Classifies changes by blast radius to route auto-merge vs mandatory human review.
125
136
  > - **Zero-Trust Base-Branch Security**: Security rules (`forbidden_paths`) are fetched exclusively from `origin/main` (never untrusted PR branches).
137
+ > - **Asset & Rules Integrity**: Guards binary assets against HTML corruption and enforces character/line budgets on rule files.
126
138
  > - **Automatic PII & Secret Redaction**: Outbound task prompts are automatically sanitized to redact API secrets and mask sensitive PII (emails, IPs, phone numbers).
127
139
  > - **Ledger Hash-Chain Integrity**: Hashing over JSONL event streams detects unauthorized log tampering or record deletions.
128
- > - **Dynamic Command Resolution (`command-resolver.mjs`)**: Auto-detects workspace boundaries (Turborepo, pnpm, Nx, Cargo, pytest, npm).
129
140
  >
130
141
  > 🔍 For a deep dive into the execution protocol, see the [Architecture & Pipeline Flow](docs/architecture.md).
131
142
 
package/bin/agentctl.mjs CHANGED
@@ -13,7 +13,7 @@ const command = args[0];
13
13
 
14
14
  function printHelp() {
15
15
  console.log(`
16
- 🚀 agentctl v0.9.0 — Universal Agent Orchestrator & Safety Gatekeeper
16
+ 🚀 agentctl v0.9.4 — Universal Agent Orchestrator & Safety Gatekeeper
17
17
 
18
18
  Usage: agentctl <command> [options]
19
19
 
@@ -22,6 +22,7 @@ Commands:
22
22
  gate | audit Run CI security and verification gate against current branch
23
23
  queue Run pending task queue
24
24
  swarm Run parallel task swarm
25
+ mcp Start stdio Model Context Protocol (MCP) server
25
26
  clean Clean stale branches, worktrees, locks, and ledgers
26
27
  lock <action> Manage mutex locks (acquire | release | status | cleanup)
27
28
  doctor Run system diagnostics and stack resolution checks
@@ -42,7 +43,7 @@ async function main() {
42
43
  }
43
44
 
44
45
  if (command === "version" || command === "--version" || command === "-v") {
45
- console.log("agentctl v0.9.0");
46
+ console.log("agentctl v0.9.4");
46
47
  process.exit(0);
47
48
  }
48
49
 
@@ -261,6 +262,12 @@ base_branch: main
261
262
  break;
262
263
  }
263
264
 
265
+ case "mcp": {
266
+ const { startMcpServer } = await import("../src/mcp.mjs");
267
+ startMcpServer();
268
+ break;
269
+ }
270
+
264
271
  default:
265
272
  console.error(`Unknown command: ${command}`);
266
273
  printHelp();
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { startMcpServer } from "../src/mcp.mjs";
4
+
5
+ startMcpServer();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jules-orchestrator-kit",
3
- "version": "0.9.3",
3
+ "version": "0.9.4",
4
4
  "description": "Orchestration kit for running Google Jules autonomous agents.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,7 +14,9 @@
14
14
  "bin": {
15
15
  "agentctl": "bin/agentctl.mjs",
16
16
  "jules-init": "bin/init.js",
17
- "jules-orchestrator-kit": "bin/agentctl.mjs"
17
+ "jules-orchestrator-kit": "bin/agentctl.mjs",
18
+ "jules-mcp": "bin/mcp-server.mjs",
19
+ "agentctl-mcp": "bin/mcp-server.mjs"
18
20
  },
19
21
  "main": "index.mjs",
20
22
  "exports": {
package/src/mcp.mjs ADDED
@@ -0,0 +1,211 @@
1
+ import { createInterface } from "node:readline";
2
+ import { loadConfig, resolveRoot, detectStack } from "./config.mjs";
3
+ import { gate, dispatch } from "./engine.mjs";
4
+ import { classifyRiskTier } from "./risk.mjs";
5
+ import { checkDailyBudget, lockStatus } from "./state.mjs";
6
+
7
+ export const MCP_SERVER_INFO = {
8
+ name: "jules-orchestrator-kit",
9
+ version: "0.9.4",
10
+ };
11
+
12
+ export const MCP_TOOLS = [
13
+ {
14
+ name: "dispatch_jules_task",
15
+ description: "Dispatch an autonomous task to the Jules AI agent provider with security bounds and budget check.",
16
+ inputSchema: {
17
+ type: "object",
18
+ properties: {
19
+ title: { type: "string", description: "Short descriptive title for the task" },
20
+ prompt: { type: "string", description: "Detailed task instructions and prompt" },
21
+ },
22
+ required: ["prompt"],
23
+ },
24
+ },
25
+ {
26
+ name: "audit_jules_gate",
27
+ description: "Run the 4-phase safety gatekeeper (Scope, Payload, Secrets, Verify) against the current workspace branch.",
28
+ inputSchema: {
29
+ type: "object",
30
+ properties: {
31
+ base: { type: "string", description: "Base branch to diff against (defaults to main)" },
32
+ fix: { type: "boolean", description: "Attempt OODA auto-repair loop on verification failure" },
33
+ allowProtected: { type: "boolean", description: "Allow edits to protected files" },
34
+ },
35
+ },
36
+ },
37
+ {
38
+ name: "check_risk_tier",
39
+ description: "Classify changed files into Risk Tiers (R0 Cosmetic, R1 Routine, R2 Consequential, R3 Restricted).",
40
+ inputSchema: {
41
+ type: "object",
42
+ properties: {
43
+ files: {
44
+ type: "array",
45
+ items: { type: "string" },
46
+ description: "List of file paths changed",
47
+ },
48
+ diffLines: { type: "number", description: "Total lines changed in diff" },
49
+ },
50
+ required: ["files"],
51
+ },
52
+ },
53
+ {
54
+ name: "get_jules_status",
55
+ description: "Retrieve orchestrator status including daily task budget, active locks, and stack diagnostics.",
56
+ inputSchema: {
57
+ type: "object",
58
+ properties: {},
59
+ },
60
+ },
61
+ ];
62
+
63
+ export async function handleMcpRequest(request, opts = {}) {
64
+ const root = opts.root || resolveRoot();
65
+ const config = opts.config || loadConfig(root);
66
+ const { id, method, params } = request;
67
+
68
+ if (method === "ping") {
69
+ return { jsonrpc: "2.0", id, result: {} };
70
+ }
71
+
72
+ if (method === "initialize") {
73
+ return {
74
+ jsonrpc: "2.0",
75
+ id,
76
+ result: {
77
+ protocolVersion: "2024-11-05",
78
+ capabilities: { tools: {} },
79
+ serverInfo: MCP_SERVER_INFO,
80
+ },
81
+ };
82
+ }
83
+
84
+ if (method === "notifications/initialized") {
85
+ return null; // Notifications produce no response
86
+ }
87
+
88
+ if (method === "tools/list") {
89
+ return {
90
+ jsonrpc: "2.0",
91
+ id,
92
+ result: { tools: MCP_TOOLS },
93
+ };
94
+ }
95
+
96
+ if (method === "tools/call") {
97
+ const toolName = params?.name;
98
+ const args = params?.arguments || {};
99
+
100
+ try {
101
+ if (toolName === "dispatch_jules_task") {
102
+ const session = await dispatch(
103
+ { title: args.title || "MCP Task Dispatch", prompt: args.prompt },
104
+ { root, config }
105
+ );
106
+ return {
107
+ jsonrpc: "2.0",
108
+ id,
109
+ result: {
110
+ content: [{ type: "text", text: JSON.stringify({ ok: true, session }, null, 2) }],
111
+ },
112
+ };
113
+ }
114
+
115
+ if (toolName === "audit_jules_gate") {
116
+ const res = await gate({
117
+ root,
118
+ config,
119
+ base: args.base || config.baseBranch || "main",
120
+ fix: args.fix || false,
121
+ allowProtected: args.allowProtected || false,
122
+ });
123
+ return {
124
+ jsonrpc: "2.0",
125
+ id,
126
+ result: {
127
+ content: [{ type: "text", text: JSON.stringify(res, null, 2) }],
128
+ },
129
+ };
130
+ }
131
+
132
+ if (toolName === "check_risk_tier") {
133
+ const tierResult = classifyRiskTier(args.files || [], { diffLines: args.diffLines || 0 });
134
+ return {
135
+ jsonrpc: "2.0",
136
+ id,
137
+ result: {
138
+ content: [{ type: "text", text: JSON.stringify(tierResult, null, 2) }],
139
+ },
140
+ };
141
+ }
142
+
143
+ if (toolName === "get_jules_status") {
144
+ const stackInfo = detectStack(root);
145
+ const budget = checkDailyBudget(root, config.limits.dailyTasks);
146
+ const locks = lockStatus(root);
147
+ const status = {
148
+ version: MCP_SERVER_INFO.version,
149
+ root,
150
+ stack: stackInfo.stack,
151
+ budget: { used: budget.used, limit: budget.budget, remaining: budget.budget - budget.used },
152
+ activeLocksCount: locks.length,
153
+ locks,
154
+ };
155
+ return {
156
+ jsonrpc: "2.0",
157
+ id,
158
+ result: {
159
+ content: [{ type: "text", text: JSON.stringify(status, null, 2) }],
160
+ },
161
+ };
162
+ }
163
+
164
+ return {
165
+ jsonrpc: "2.0",
166
+ id,
167
+ error: { code: -32601, message: `Unknown tool: ${toolName}` },
168
+ };
169
+ } catch (err) {
170
+ return {
171
+ jsonrpc: "2.0",
172
+ id,
173
+ result: {
174
+ content: [{ type: "text", text: JSON.stringify({ ok: false, error: err.message }, null, 2) }],
175
+ isError: true,
176
+ },
177
+ };
178
+ }
179
+ }
180
+
181
+ return {
182
+ jsonrpc: "2.0",
183
+ id,
184
+ error: { code: -32601, message: `Method not found: ${method}` },
185
+ };
186
+ }
187
+
188
+ export function startMcpServer(input = process.stdin, output = process.stdout, opts = {}) {
189
+ const rl = createInterface({ input, output: null, terminal: false });
190
+
191
+ rl.on("line", async (line) => {
192
+ const trimmed = line.trim();
193
+ if (!trimmed) return;
194
+
195
+ try {
196
+ const request = JSON.parse(trimmed);
197
+ const response = await handleMcpRequest(request, opts);
198
+ if (response !== null) {
199
+ output.write(JSON.stringify(response) + "\n");
200
+ }
201
+ } catch (err) {
202
+ output.write(
203
+ JSON.stringify({
204
+ jsonrpc: "2.0",
205
+ id: null,
206
+ error: { code: -32700, message: `Parse error: ${err.message}` },
207
+ }) + "\n"
208
+ );
209
+ }
210
+ });
211
+ }
package/src/state.mjs CHANGED
@@ -98,10 +98,18 @@ export function checkDailyBudget(arg1 = resolveRoot(), arg2 = 300) {
98
98
  }
99
99
  }
100
100
 
101
+ export class BudgetError extends Error {
102
+ constructor(message) {
103
+ super(message);
104
+ this.name = "BudgetError";
105
+ this.code = 7;
106
+ }
107
+ }
108
+
101
109
  export async function withBudget(fn, root = resolveRoot(), limit = 300) {
102
110
  const budget = checkDailyBudget(root, limit);
103
111
  if (!budget.ok) {
104
- throw new Error(`Daily budget exhausted (${budget.used}/${budget.budget} tasks executed)`);
112
+ throw new BudgetError(`Daily budget exhausted (${budget.used}/${budget.budget} tasks executed)`);
105
113
  }
106
114
  return fn();
107
115
  }