jules-orchestrator-kit 0.32.3 → 0.32.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.
- package/README.md +46 -10
- package/bin/agentctl.mjs +124 -13
- package/index.mjs +28 -4
- package/package.json +3 -3
- package/scripts/command-resolver.mjs +15 -1
- package/scripts/jules-merge-swarm.mjs +1 -1
- package/src/config.mjs +48 -3
- package/src/dag-engine.mjs +118 -0
- package/src/engine.mjs +239 -73
- package/src/evidence.mjs +435 -0
- package/src/mcp.mjs +39 -1
- package/src/memory.mjs +2 -2
- package/src/ops/evidence-actions.mjs +74 -0
- package/src/provider.mjs +37 -7
- package/src/router.mjs +200 -0
- package/src/security.mjs +55 -1
- package/src/stack-detector.mjs +372 -21
- package/src/wizard-task.mjs +66 -5
package/README.md
CHANGED
|
@@ -108,13 +108,19 @@ Autonomous coding agents can write software at 100× human speed—but unconstra
|
|
|
108
108
|
|
|
109
109
|
* **💻 Native Interactive UX & Command Palette (`v0.30.0`):** Features a zero-dependency full-screen Terminal Engine (`capabilities`, `key-decoder`, `renderer`, `layout`, `widgets`), interactive diagnostic matrix (`agentctl doctor`), task queue/swarm managers (`agentctl queue`, `agentctl swarm`), and a searchable Command Palette.
|
|
110
110
|
|
|
111
|
-
* **🌐 Universal Polyglot Spine:** Natively auto-detects
|
|
111
|
+
* **🌐 Universal Polyglot Spine:** Natively auto-detects 26+ tech stacks (PHP/Laravel/WordPress, .NET/C#, Python, Go, Rust, C/C++, Flutter/Swift, Node/Deno/Bun, Solidity/Foundry/Hardhat) and transparently wraps verification suites in Docker Compose or Devcontainer sandboxes.
|
|
112
|
+
|
|
113
|
+
* **🧩 DAG-Ordered Task Queue & Specialist Agent Roles:** `agentctl queue --dag` resolves inter-task dependencies via Kahn's algorithm with cycle detection instead of linear FIFO order, and `--role <overseer|bolt|sentinel|janitor>` binds a task to a pre-defined specialist prompt persona resolved from `.agent/prompts/`.
|
|
114
|
+
|
|
115
|
+
* **🔏 Cryptographic Evidence Ledger (`agentctl evidence`):** Generates a SHA-256 manifest of changed files, test-file hashes, and tamper-detection locks for every verified task — a portable, offline-verifiable audit trail toward the roadmap's SOC2 compliance exporter.
|
|
116
|
+
|
|
117
|
+
* **💸 Dynamic Complexity & Cost Router (`router:` in `.agent/config.yml`, opt-in):** A zero-dependency, rule-based heuristic classifier (`src/router.mjs`) routes trivial tasks (typos, lint fixes, single-file lockfile bumps) to a cheap/fast provider — e.g. the built-in `gemini-flash` (Gemini CLI, headless mode) preset — while reserving your primary provider for complex, multi-file, or safety-sensitive work. Tasks touching `scope.deny`, `auth/**`, `migrations/**`, secrets, or using the `sentinel` role always force the primary provider regardless of score. Fully provider-agnostic: swap in any exec/HTTP provider spec for `router.fast`/`router.complex`, and override per-task with `--tier fast|complex`.
|
|
112
118
|
|
|
113
119
|
* **📂 Scoped Monorepo Boundary Resolver:** Statically maps changed files up directory ancestry to invoke isolated subshell test suites (`(cd backend && pytest) && (cd cli && cargo test)`), eliminating global test thrashing.
|
|
114
120
|
|
|
115
121
|
* **🚀 Zero-Test Bootstrapping (`agentctl bootstrap`):** Synthesizes deterministic syntax-check and smoke-test verification oracles for untested legacy repositories so agents always operate against a falsifiable feedback loop.
|
|
116
122
|
|
|
117
|
-
* **📈 Proven Scale & Reliability:** Empirically tested with **
|
|
123
|
+
* **📈 Proven Scale & Reliability:** Empirically tested with **421 unit tests across 59 suites passing in < 8.0s**, supporting 300+ daily agent sessions per repository.
|
|
118
124
|
|
|
119
125
|
<br/>
|
|
120
126
|
|
|
@@ -166,7 +172,7 @@ To ensure maximum merge success, dispatch tasks according to our deterministic t
|
|
|
166
172
|
| **Self-Healing Loop** | ❌ None (Crashes on test error) | ❌ None (Fails build; notifies human) | ✅ **Autonomous OODA Loop** (Max 3 repair turns with error fingerprinting) |
|
|
167
173
|
| **Interactive UX Engine**| ❌ Raw unformatted CLI dumps | ❌ Non-interactive log outputs | ✅ **Native TUI Engine & Command Palette** (Zero-dependency alternate-screen TUI) |
|
|
168
174
|
| **Scope Isolation** | ❌ None (Can modify CI files or lockfiles) | 🟡 Post-commit branch rules only | ✅ **Fail-Closed Scope Guard** (Deny-first evaluation; blocks protected paths) |
|
|
169
|
-
| **Polyglot Stack Detection**| ❌ Manual prompt instructions | 🟡 Hardcoded YAML workflow steps | ✅ **Universal
|
|
175
|
+
| **Polyglot Stack Detection**| ❌ Manual prompt instructions | 🟡 Hardcoded YAML workflow steps | ✅ **Universal 26+ Stack Detector** (`src/config.mjs`) |
|
|
170
176
|
| **Flaky Test Quarantine** | ❌ Fails session randomly | ❌ Breaks CI pipeline randomly | ✅ **Wilson-Score Statistical Quarantine** (Oscillation ≥ 0.40 quarantined automatically) |
|
|
171
177
|
| **Monorepo Scoping** | ❌ Runs full global test suite | 🟡 Requires custom Nx/Turbo scripting | ✅ **Scoped Subshell Boundary Resolver** (`resolveWorkspaceBoundary`) |
|
|
172
178
|
| **Zero-Test Bootstrapping**| ❌ Halts without verification oracle | ❌ Fails build if no tests exist | ✅ **Instant Oracle Synthesis** (`php -l`, `compileall`, `dotnet build`, `tsc`, `smoke`) |
|
|
@@ -227,7 +233,7 @@ npx jules-orchestrator-kit queue --interactive
|
|
|
227
233
|
<br/>
|
|
228
234
|
|
|
229
235
|
<details>
|
|
230
|
-
<summary><b>🔍 View All
|
|
236
|
+
<summary><b>🔍 View All 26+ Supported Ecosystems & Stack Triggers</b></summary>
|
|
231
237
|
|
|
232
238
|
<br/>
|
|
233
239
|
|
|
@@ -242,6 +248,8 @@ Ecosystems Natively Supported by src/config.mjs:
|
|
|
242
248
|
├── Systems / Rust Cargo (Cargo.toml)
|
|
243
249
|
├── Systems / Go (go.mod)
|
|
244
250
|
├── Systems / Make (Makefile)
|
|
251
|
+
├── Web3 / Solidity Foundry (foundry.toml, remappings.txt) — offline-enforced forge test/build/fmt
|
|
252
|
+
├── Web3 / Solidity Hardhat (hardhat.config.js, hardhat.config.ts)
|
|
245
253
|
├── Python / FastAPI / Django (pyproject.toml, requirements.txt, setup.py)
|
|
246
254
|
├── Elixir / Phoenix (mix.exs)
|
|
247
255
|
├── Ruby / Rails (Gemfile)
|
|
@@ -269,7 +277,7 @@ Ecosystems Natively Supported by src/config.mjs:
|
|
|
269
277
|
# .agent/config.yml — Universal Orchestrator Configuration
|
|
270
278
|
|
|
271
279
|
version: 1
|
|
272
|
-
provider: "jules" # Provider key ("jules" | "claude-code" | "
|
|
280
|
+
provider: "jules" # Provider key ("jules" | "claude-code" | "codex" | "gemini-flash")
|
|
273
281
|
baseBranch: "main" # Default target base branch
|
|
274
282
|
branchPrefix: "agent/" # Prefix for task branches
|
|
275
283
|
|
|
@@ -292,6 +300,15 @@ limits:
|
|
|
292
300
|
dailyTasks: 300 # Daily task session quota limit
|
|
293
301
|
repairAttempts: 3 # Maximum OODA repair iterations
|
|
294
302
|
concurrency: 1 # Worker slot concurrency limit
|
|
303
|
+
|
|
304
|
+
# Dynamic Complexity & Cost Router — opt-in, disabled by default.
|
|
305
|
+
# Provider-agnostic: "fast"/"complex" accept any provider key ("jules" |
|
|
306
|
+
# "claude-code" | "codex" | "gemini-flash") or an inline custom provider spec.
|
|
307
|
+
router:
|
|
308
|
+
enabled: false
|
|
309
|
+
fast: "gemini-flash" # Trivial/mechanical tasks (score <= threshold)
|
|
310
|
+
complex: "jules" # Complex/multi-file/safety-sensitive tasks; defaults to `provider`
|
|
311
|
+
threshold: 0 # Heuristic score above which a task escalates to `complex`
|
|
295
312
|
```
|
|
296
313
|
|
|
297
314
|
<br/>
|
|
@@ -369,15 +386,15 @@ Native stdio server exposing task dispatch, gate verification, and risk auditing
|
|
|
369
386
|
| Command | Usage | Description | Exit Codes |
|
|
370
387
|
| :--- | :--- | :--- | :--- |
|
|
371
388
|
| `init` | `agentctl init [--interactive] [--tier pro]` | Interactive onboarding wizard & stack oracle inspector generating `.agent/config.yml`. | `0` (Created) |
|
|
372
|
-
| `task create` | `agentctl task create [--title <t>] [--prompt <p>] [--template <id>]` | Interactively authors & scopes falsifiable task envelopes with secret scrubbing
|
|
389
|
+
| `task create` | `agentctl task create [--title <t>] [--prompt <p>] [--template <id>] [--role <name>] [--tier fast\|complex] [--depends-on <id,...>]` | Interactively authors & scopes falsifiable task envelopes with secret scrubbing, preflight gate checks, specialist role resolution, DAG dependency wiring, and an optional Cost Router tier override. | `0` (Queued), `1` (Unfalsifiable / Secret leak) |
|
|
373
390
|
| `task template` | `agentctl task template [<id>] [--list] [--json]` | Lists and synthesizes specialized web task envelopes (`web-cwv`, `web-wcag`, `web-seo`, `web-playwright`, `web-flaky-heal`). | `0` (Synthesized/Listed) |
|
|
374
391
|
| `task optimize` | `agentctl task optimize "<prompt>" [--fix] [--web] [--json]` | Linter & optimizer injecting Google Labs 3-phase exploration budgets, critic steering, and web oracles. | `0` (Scored/Fixed) |
|
|
375
392
|
| `test-gen` | `agentctl test-gen --title <t> --spec <s> [--run]` | Scaffolds falsifiable unit tests, verifies **RED** failure state, and locks test in `scope.deny`. | `0` (Scaffolded/Red) |
|
|
376
393
|
| `rollback` | `agentctl rollback [sessionId \| --latest]` | Restores exact commit, uncommitted files, and cleans orphan task worktrees from pre-flight checkpoints. | `0` (Restored), `1` (Error) |
|
|
377
394
|
| `resume` | `agentctl resume <sessionId> --response "<reply>"` | Streams engineer response back into active Google Jules warm session context window. | `0` (Resumed), `1` (Error) |
|
|
378
|
-
| `dispatch` | `agentctl dispatch --title <t> --prompt <p
|
|
395
|
+
| `dispatch` | `agentctl dispatch --title <t> --prompt <p> [--role <name>] [--tier fast\|complex]` | Dispatches a single task to an AI agent in an isolated worktree, optionally binding a specialist role prompt (`overseer`\|`bolt`\|`sentinel`\|`janitor`) and/or overriding the Cost Router tier. | `0` (Success), `1` (Arg error), `2` (429 Rate limit), `3` (Scope deny), `4` (OODA exhausted), `5` (Diff > 75KB), `6` (Secret leak) |
|
|
379
396
|
| `doctor` | `agentctl doctor [--interactive] [--fix safe]` | Diagnostic DAG check runner & automated transactional repair planner. | `0` (Healthy) |
|
|
380
|
-
| `queue` | `agentctl queue [--interactive] [--json]` | Consumes, inspects, and executes task envelopes in `.agent/jules-queue
|
|
397
|
+
| `queue` | `agentctl queue [--interactive] [--dag] [--concurrency <n>] [--json]` | Consumes, inspects, and executes task envelopes in `.agent/jules-queue/`; `--dag` resolves inter-task dependencies via Kahn's algorithm with cycle detection instead of linear FIFO order (supports `--json`). | `0` (Complete) |
|
|
381
398
|
| `swarm` | `agentctl swarm [--interactive] [--json]` | Runs parallel multi-agent swarm across worker slots with process PID liveness detection (supports `--json`). | `0` (Complete) |
|
|
382
399
|
| `scan` | `agentctl scan` | Scans codebase for TODO/FIXME annotations to seed task authoring. | `0` (Scanned) |
|
|
383
400
|
| `review-repair`| `agentctl review-repair <pr-comments.json>`| Parses GitHub PR review comments and synthesizes actionable OODA repair tasks. | `0` (Parsed), `1` (Missing file) |
|
|
@@ -386,9 +403,10 @@ Native stdio server exposing task dispatch, gate verification, and risk auditing
|
|
|
386
403
|
| `bootstrap` | `agentctl bootstrap [--force] [--json]` | Inspects an untested repository and synthesizes `.agent/config.yml` with a zero-test verification oracle (`php -l`, `compileall`, `dotnet build`, `tsc`, `smoke`). | `0` (Bootstrapped / Existing) |
|
|
387
404
|
| `lock` | `agentctl lock <acquire\|release\|status>`| Manages VFS mutex locks for multi-agent non-overlapping file ownership. | `0` (Locked/Released), `1` (Conflict) |
|
|
388
405
|
| `clean` | `agentctl clean` | Prunes stale git worktrees, lockfiles, and temporary ledgers. | `0` (Clean) |
|
|
406
|
+
| `evidence` | `agentctl evidence <generate\|verify\|show> [--manifest <path>] [--json]` | Generates, verifies, or prints a SHA-256 cryptographic evidence manifest (changed-file hashes + test-file tamper lock) for audit trails. | `0` (Verified/Generated), `1` (Tamper detected / Verification failed) |
|
|
389
407
|
| `mcp` | `agentctl mcp` | Starts stdio Model Context Protocol (MCP) server for tool integration. | `0` / Stdio stream |
|
|
390
408
|
| `mcp init` | `agentctl mcp init [--target cursor\|vscode\|claude\|all]` | 1-click scaffolding for Cursor (`.cursor/mcp.json`), VS Code tasks (`tasks.json`), and Claude Desktop. | `0` (Scaffolded) |
|
|
391
|
-
| `version` | `agentctl version` | Outputs orchestrator kit semantic version (`v0.32.
|
|
409
|
+
| `version` | `agentctl version` | Outputs orchestrator kit semantic version (`v0.32.5`). | `0` |
|
|
392
410
|
|
|
393
411
|
<br/>
|
|
394
412
|
|
|
@@ -419,7 +437,23 @@ const result = await provider.dispatch(
|
|
|
419
437
|
);
|
|
420
438
|
```
|
|
421
439
|
|
|
422
|
-
### 3.
|
|
440
|
+
### 3. Dynamic Complexity & Cost Router (`resolveRoutedProvider`)
|
|
441
|
+
Opt-in, config-driven routing between a cheap/fast provider and your primary provider — see [Configuration Reference](#configuration) for the `router:` block. Programmatic usage mirrors `createFailoverProvider`:
|
|
442
|
+
|
|
443
|
+
```javascript
|
|
444
|
+
import { resolveRoutedProvider, loadConfig } from "jules-orchestrator-kit";
|
|
445
|
+
|
|
446
|
+
const config = loadConfig(process.cwd()); // router.enabled must be true in .agent/config.yml
|
|
447
|
+
const { provider, classification } = resolveRoutedProvider(
|
|
448
|
+
{ title: "Fix typo", prompt: "Fix a typo in the README." },
|
|
449
|
+
config
|
|
450
|
+
);
|
|
451
|
+
console.log(classification.tier); // "fast" | "complex"
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
Ships with a `gemini-flash` preset (Gemini CLI headless mode, `gemini-3.6-flash`) as a batteries-included fast tier, but any provider key or custom spec works for `router.fast`/`router.complex` — the router is provider-agnostic by design, not tied to any single vendor.
|
|
455
|
+
|
|
456
|
+
### 4. Model Context Protocol (MCP) Server
|
|
423
457
|
Expose orchestrator gates and queue controls over stdio to client tools (Antigravity, Claude, Cursor):
|
|
424
458
|
```bash
|
|
425
459
|
npx jules-orchestrator-kit mcp
|
|
@@ -436,6 +470,8 @@ npx jules-orchestrator-kit mcp
|
|
|
436
470
|
|
|
437
471
|
| Feature | Module / Command | Architectural Description | Target Release |
|
|
438
472
|
| :--- | :--- | :--- | :---: |
|
|
473
|
+
| **Dynamic Complexity & Cost Router** | `src/router.mjs`, `router:` in `.agent/config.yml` | Provider-agnostic, zero-dependency heuristic classifier routing trivial tasks to a fast/cheap provider (`gemini-flash` preset included) and complex/safety-sensitive tasks to the primary provider; opt-in, `--tier` override. | **Unreleased** *(main)* |
|
|
474
|
+
| **DAG Task Queue, Specialist Roles & Evidence Ledger** | `src/dag-engine.mjs`, `src/evidence.mjs`, `agentctl evidence` | Kahn's-algorithm dependency-ordered queue execution (`queue --dag`), `--role` specialist prompt resolution, and SHA-256 cryptographic evidence manifests with test-tamper locking. | **Unreleased** *(main)* |
|
|
439
475
|
| **Warm Session Resumption & PR Bundler** | `src/provider.mjs`, `src/engine.mjs` | Multi-turn warm session context streaming via `POST /v1alpha/sessions/{id}:sendMessage` & evidence PR descriptions. | **v0.31.0** *(Shipped)* |
|
|
440
476
|
| **TDD Harness & Prompt Falsifiability Linter** | `agentctl test-gen`, `agentctl task optimize` | Automated RED-state test generator, `scope.deny` test locking, and prompt testability linter with fuzzy path resolution. | **v0.31.0** *(Shipped)* |
|
|
441
477
|
| **Atomic Git Checkpoint & Rollback** | `agentctl rollback` (`src/ops/checkpoint.mjs`) | Pre-flight git HEAD/stash snapshotting, atomic rollback restoration, and 10-session pruning rotation. | **v0.31.0** *(Shipped)* |
|
package/bin/agentctl.mjs
CHANGED
|
@@ -12,16 +12,18 @@ import { reapOrphanedIntents, reapStaleMutexDirs } from "../src/journal.mjs";
|
|
|
12
12
|
const args = process.argv.slice(2);
|
|
13
13
|
const command = args[0];
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
export const VERSION = "0.32.5";
|
|
16
|
+
|
|
17
|
+
export function printHelp() {
|
|
16
18
|
console.log(`
|
|
17
|
-
🚀 agentctl v0.32.
|
|
19
|
+
🚀 agentctl v0.32.5 — Universal Agent Orchestrator & Safety Gatekeeper
|
|
18
20
|
|
|
19
21
|
Usage: agentctl <command> [options]
|
|
20
22
|
|
|
21
23
|
Commands:
|
|
22
|
-
dispatch | create Dispatch a single task to an AI agent
|
|
24
|
+
dispatch | create Dispatch a single task to an AI agent (--role <name>, --tier fast|complex)
|
|
23
25
|
gate | audit Run CI security and verification gate against current branch
|
|
24
|
-
queue Run pending task queue
|
|
26
|
+
queue Run pending task queue (--dag, --concurrency <n>)
|
|
25
27
|
swarm Run parallel task swarm
|
|
26
28
|
mcp Start stdio Model Context Protocol (MCP) server
|
|
27
29
|
clean Clean stale branches, worktrees, locks, and ledgers
|
|
@@ -31,7 +33,7 @@ Commands:
|
|
|
31
33
|
review-repair Parse PR review comments and synthesize OODA repair tasks
|
|
32
34
|
dashboard Start local HTTP telemetry and audit dashboard
|
|
33
35
|
init Scaffold .agent/ config and run onboarding wizard
|
|
34
|
-
task create Interactively author and scope a Jules task envelope (--template <name
|
|
36
|
+
task create Interactively author and scope a Jules task envelope (--template <name>, --role <name>, --tier fast|complex)
|
|
35
37
|
task optimize Linter & optimizer for Jules task prompts (--fix, --json, --web)
|
|
36
38
|
task template List and generate web development task templates (--list, --json)
|
|
37
39
|
test-gen Scaffold & run automated TDD Red-to-Green test cycle (--run)
|
|
@@ -43,9 +45,13 @@ Commands:
|
|
|
43
45
|
hydrate [prompt] Prepend active system learnings and baton-pass state to a prompt
|
|
44
46
|
harvest Harvest failure traces and record/quarantine resolution rules
|
|
45
47
|
learning add Record a system learning rule into .agent/knowledge/
|
|
48
|
+
evidence <action> Manage cryptographic audit evidence (generate | verify | show)
|
|
46
49
|
version Output agentctl version
|
|
47
50
|
|
|
48
51
|
Options:
|
|
52
|
+
--role, -r Specify specialist agent role (overseer | bolt | sentinel | janitor)
|
|
53
|
+
--tier Force routing tier when router.enabled (fast | complex) — see .agent/config.yml router:
|
|
54
|
+
--dag Execute queue tasks via DAG dependency resolution
|
|
49
55
|
--dry-run, -d Simulate action without making API calls or modifying git
|
|
50
56
|
--mode, -m Gate evaluation mode (working-tree | committed | staged)
|
|
51
57
|
--repoless Dispatch task in repoless execution mode
|
|
@@ -63,7 +69,7 @@ async function main() {
|
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
if (command === "version" || command === "--version" || command === "-v") {
|
|
66
|
-
console.log("agentctl v0.32.
|
|
72
|
+
console.log("agentctl v0.32.5");
|
|
67
73
|
process.exit(0);
|
|
68
74
|
}
|
|
69
75
|
|
|
@@ -81,6 +87,8 @@ async function main() {
|
|
|
81
87
|
title: { type: "string", short: "t" },
|
|
82
88
|
prompt: { type: "string", short: "p" },
|
|
83
89
|
"prompt-file": { type: "string", short: "f" },
|
|
90
|
+
role: { type: "string", short: "r" },
|
|
91
|
+
tier: { type: "string" },
|
|
84
92
|
source: { type: "string", short: "s" },
|
|
85
93
|
branch: { type: "string", short: "b" },
|
|
86
94
|
repoless: { type: "boolean" },
|
|
@@ -109,6 +117,8 @@ async function main() {
|
|
|
109
117
|
const task = {
|
|
110
118
|
title: values.title || "CLI Dispatch Task",
|
|
111
119
|
prompt: promptContent,
|
|
120
|
+
role: values.role,
|
|
121
|
+
tier: values.tier === "fast" || values.tier === "complex" ? values.tier : undefined,
|
|
112
122
|
source: values.source,
|
|
113
123
|
branch: values.branch,
|
|
114
124
|
repoless: values.repoless,
|
|
@@ -131,6 +141,9 @@ async function main() {
|
|
|
131
141
|
console.log(`\n✅ Task Dispatched Successfully!`);
|
|
132
142
|
console.log(` Session ID : ${session.id}`);
|
|
133
143
|
console.log(` Session URL : ${session.url || "N/A"}`);
|
|
144
|
+
if (session._routeTier) {
|
|
145
|
+
console.log(` Router Tier : ${session._routeTier} (${session._routeReason || "n/a"})`);
|
|
146
|
+
}
|
|
134
147
|
}
|
|
135
148
|
process.exit(0);
|
|
136
149
|
} catch (err) {
|
|
@@ -200,17 +213,34 @@ async function main() {
|
|
|
200
213
|
}
|
|
201
214
|
|
|
202
215
|
case "queue": {
|
|
216
|
+
const { values } = parseArgs({
|
|
217
|
+
args: args.slice(1),
|
|
218
|
+
options: {
|
|
219
|
+
dag: { type: "boolean" },
|
|
220
|
+
concurrency: { type: "string", short: "c" },
|
|
221
|
+
"dry-run": { type: "boolean", short: "d" },
|
|
222
|
+
json: { type: "boolean", short: "j" },
|
|
223
|
+
},
|
|
224
|
+
allowPositionals: true,
|
|
225
|
+
});
|
|
226
|
+
|
|
203
227
|
const queueDir = getQueueDir(root);
|
|
204
228
|
const files = readdirSync(queueDir).filter((f) => isTaskFile(f, queueDir));
|
|
205
229
|
console.log(`Found ${files.length} queued task(s) in .agent/queue/`);
|
|
206
230
|
if (files.length > 0) {
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
231
|
+
const concurrency = values.concurrency ? Number(values.concurrency) : undefined;
|
|
232
|
+
const results = await run(null, {
|
|
233
|
+
root,
|
|
234
|
+
config,
|
|
235
|
+
dag: values.dag,
|
|
236
|
+
concurrency,
|
|
237
|
+
dryRun: values["dry-run"],
|
|
238
|
+
});
|
|
239
|
+
if (values.json) {
|
|
240
|
+
console.log(JSON.stringify(results, null, 2));
|
|
241
|
+
} else {
|
|
242
|
+
console.log(`\nProcessed ${results.processed || results.results?.length || 0} task(s).`);
|
|
243
|
+
}
|
|
214
244
|
}
|
|
215
245
|
process.exit(0);
|
|
216
246
|
break;
|
|
@@ -372,7 +402,11 @@ async function main() {
|
|
|
372
402
|
options: {
|
|
373
403
|
title: { type: "string", short: "t" },
|
|
374
404
|
prompt: { type: "string", short: "p" },
|
|
405
|
+
role: { type: "string", short: "r" },
|
|
406
|
+
tier: { type: "string" },
|
|
375
407
|
template: { type: "string" },
|
|
408
|
+
depends: { type: "string" },
|
|
409
|
+
"depends-on": { type: "string" },
|
|
376
410
|
"verify-cmd": { type: "string", short: "v" },
|
|
377
411
|
"auto-pr": { type: "boolean" },
|
|
378
412
|
"require-plan-approval": { type: "boolean" },
|
|
@@ -386,7 +420,10 @@ async function main() {
|
|
|
386
420
|
const res = await runTaskCreateWizard(root, {
|
|
387
421
|
title: values.title,
|
|
388
422
|
prompt: values.prompt,
|
|
423
|
+
role: values.role,
|
|
424
|
+
tier: values.tier,
|
|
389
425
|
template: values.template,
|
|
426
|
+
dependsOn: values["depends-on"] || values.depends,
|
|
390
427
|
verifyCmd: values["verify-cmd"],
|
|
391
428
|
autoPr: values["auto-pr"],
|
|
392
429
|
requirePlanApproval: values["require-plan-approval"],
|
|
@@ -399,6 +436,9 @@ async function main() {
|
|
|
399
436
|
console.log(`✅ Task synthesized & queued at ${res.taskFile}`);
|
|
400
437
|
console.log(` Task ID : ${res.plan.taskId}`);
|
|
401
438
|
console.log(` Title : ${res.plan.title}`);
|
|
439
|
+
if (res.plan.role) console.log(` Role : ${res.plan.role}`);
|
|
440
|
+
if (res.plan.tier) console.log(` Tier : ${res.plan.tier} (routing override)`);
|
|
441
|
+
if (res.plan.dependsOn && res.plan.dependsOn.length > 0) console.log(` DependsOn: ${res.plan.dependsOn.join(", ")}`);
|
|
402
442
|
console.log(` Auto-PR : ${res.plan.flags.autoPr}`);
|
|
403
443
|
}
|
|
404
444
|
process.exit(0);
|
|
@@ -748,6 +788,77 @@ async function main() {
|
|
|
748
788
|
process.exit(1);
|
|
749
789
|
}
|
|
750
790
|
|
|
791
|
+
case "evidence": {
|
|
792
|
+
const subAction = args[1] || "show";
|
|
793
|
+
const { planEvidenceGenerate, planEvidenceVerify, planEvidenceShow } = await import("../src/ops/evidence-actions.mjs");
|
|
794
|
+
const { values } = parseArgs({
|
|
795
|
+
args: args.slice(2),
|
|
796
|
+
options: {
|
|
797
|
+
output: { type: "string", short: "o" },
|
|
798
|
+
manifest: { type: "string", short: "m" },
|
|
799
|
+
markdown: { type: "string" },
|
|
800
|
+
json: { type: "boolean", short: "j" },
|
|
801
|
+
},
|
|
802
|
+
allowPositionals: true,
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
if (subAction === "generate" || subAction === "create") {
|
|
806
|
+
const res = planEvidenceGenerate(root, {
|
|
807
|
+
output: values.output,
|
|
808
|
+
markdownOutput: values.markdown,
|
|
809
|
+
});
|
|
810
|
+
if (values.json) {
|
|
811
|
+
console.log(JSON.stringify(res, null, 2));
|
|
812
|
+
} else {
|
|
813
|
+
console.log(`\n🛡️ Cryptographic Evidence Manifest Generated!`);
|
|
814
|
+
console.log(` Manifest ID : ${res.manifest.manifestId}`);
|
|
815
|
+
console.log(` Signature : ${res.manifest.evidenceHash}`);
|
|
816
|
+
console.log(` Location : ${res.manifestPath}`);
|
|
817
|
+
console.log(` Test Files : ${res.manifest.testIntegrity.testFileCount}`);
|
|
818
|
+
console.log(` Tampered : ${res.manifest.testIntegrity.tamperDetected ? "YES (FAILED)" : "NO (VERIFIED)"}\n`);
|
|
819
|
+
}
|
|
820
|
+
process.exit(res.manifest.testIntegrity.tamperDetected ? 1 : 0);
|
|
821
|
+
} else if (subAction === "verify" || subAction === "check") {
|
|
822
|
+
const res = planEvidenceVerify(root, {
|
|
823
|
+
manifest: values.manifest,
|
|
824
|
+
});
|
|
825
|
+
if (values.json) {
|
|
826
|
+
console.log(JSON.stringify(res, null, 2));
|
|
827
|
+
} else {
|
|
828
|
+
if (res.ok) {
|
|
829
|
+
console.log(`\n✅ Evidence Verification PASSED`);
|
|
830
|
+
console.log(` Manifest ID : ${res.manifestId}`);
|
|
831
|
+
console.log(` Signature : ${res.evidenceHash}\n`);
|
|
832
|
+
} else {
|
|
833
|
+
console.error(`\n❌ Evidence Verification FAILED`);
|
|
834
|
+
console.error(` Reason : ${res.reason}`);
|
|
835
|
+
if (res.details) {
|
|
836
|
+
console.error(` Details : ${JSON.stringify(res.details)}\n`);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
process.exit(res.ok ? 0 : 1);
|
|
841
|
+
} else if (subAction === "show" || subAction === "print") {
|
|
842
|
+
const res = planEvidenceShow(root, {
|
|
843
|
+
manifest: values.manifest,
|
|
844
|
+
});
|
|
845
|
+
if (values.json) {
|
|
846
|
+
console.log(JSON.stringify(res, null, 2));
|
|
847
|
+
} else {
|
|
848
|
+
if (res.ok) {
|
|
849
|
+
console.log(`\n${res.markdown}\n`);
|
|
850
|
+
} else {
|
|
851
|
+
console.error(`\n❌ Failed to show evidence: ${res.reason}\n`);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
process.exit(res.ok ? 0 : 1);
|
|
855
|
+
} else {
|
|
856
|
+
console.error(`Unknown evidence subaction: ${subAction}. Use generate | verify | show.`);
|
|
857
|
+
process.exit(1);
|
|
858
|
+
}
|
|
859
|
+
break;
|
|
860
|
+
}
|
|
861
|
+
|
|
751
862
|
default:
|
|
752
863
|
console.error(`Unknown command: ${command}`);
|
|
753
864
|
printHelp();
|
package/index.mjs
CHANGED
|
@@ -13,6 +13,8 @@ export {
|
|
|
13
13
|
matchesGlob,
|
|
14
14
|
checkScope,
|
|
15
15
|
scanDiff,
|
|
16
|
+
checkEdgeRuntimeImports,
|
|
17
|
+
checkCrossPackageImports,
|
|
16
18
|
} from "./src/security.mjs";
|
|
17
19
|
export { sanitizeUntrustedData, buildAgentEnvelope } from "./src/prompt-guard.mjs";
|
|
18
20
|
export { isolateMcpStdout, writeMcpFrame } from "./src/mcp.mjs";
|
|
@@ -29,7 +31,14 @@ export {
|
|
|
29
31
|
ProviderSchemaError,
|
|
30
32
|
parseRetryAfter,
|
|
31
33
|
} from "./src/provider.mjs";
|
|
32
|
-
export {
|
|
34
|
+
export {
|
|
35
|
+
detectPolyglotStack,
|
|
36
|
+
resolveWorkspaceBoundary,
|
|
37
|
+
bootstrapZeroTestRepo,
|
|
38
|
+
findSubprojectRoot,
|
|
39
|
+
detectCrossPackageBoundaryViolations,
|
|
40
|
+
detectCircularDependencies,
|
|
41
|
+
} from "./src/stack-detector.mjs";
|
|
33
42
|
export {
|
|
34
43
|
appendLedger,
|
|
35
44
|
readLedger,
|
|
@@ -100,9 +109,24 @@ export { synthesizePrDescription, probeDevServer } from "./src/engine.mjs";
|
|
|
100
109
|
// Automated TDD Red-to-Green Harness
|
|
101
110
|
export { scaffoldTddTest, runTddCycle, TddError } from "./src/ops/tdd-generator.mjs";
|
|
102
111
|
|
|
103
|
-
//
|
|
104
|
-
export {
|
|
105
|
-
|
|
112
|
+
// SPORE Memory & System Learnings
|
|
113
|
+
export { recordLearning, loadLearnings, hydratePrompt, harvestFailure, getLearningsPath, getSystemLearningsMdPath } from "./src/memory.mjs";
|
|
106
114
|
|
|
115
|
+
// Specialist Role Resolution & DAG Queue Execution
|
|
116
|
+
export { resolveRolePrompt } from "./src/wizard-task.mjs";
|
|
117
|
+
export { executeQueueDag, resolveAffectedTests } from "./src/dag-engine.mjs";
|
|
107
118
|
|
|
119
|
+
// IDE Native MCP Scaffolder
|
|
120
|
+
export { scaffoldIdeConfig, IdeScaffoldError } from "./src/ops/ide-scaffold.mjs";
|
|
108
121
|
|
|
122
|
+
// Cryptographic Evidence & Test Integrity Manifests
|
|
123
|
+
export {
|
|
124
|
+
computeFileHash,
|
|
125
|
+
computeDirectoryHash,
|
|
126
|
+
generateEvidenceManifest,
|
|
127
|
+
writeEvidenceManifest,
|
|
128
|
+
loadEvidenceManifest,
|
|
129
|
+
verifyEvidenceManifest,
|
|
130
|
+
generateEvidenceMarkdown,
|
|
131
|
+
computeEvidenceHash,
|
|
132
|
+
} from "./src/evidence.mjs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jules-orchestrator-kit",
|
|
3
|
-
"version": "0.32.
|
|
3
|
+
"version": "0.32.5",
|
|
4
4
|
"description": "Orchestration kit for running Google Jules autonomous agents.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"author": "FullThrottle83",
|
|
71
71
|
"license": "MIT",
|
|
72
72
|
"devDependencies": {
|
|
73
|
-
"eslint": "^
|
|
74
|
-
"globals": "^17.
|
|
73
|
+
"eslint": "^10.8.1",
|
|
74
|
+
"globals": "^17.11.0"
|
|
75
75
|
}
|
|
76
76
|
}
|
|
@@ -22,7 +22,13 @@ export function parseYamlConfig(root = process.cwd()) {
|
|
|
22
22
|
if (parsed && (parsed.test_cmd || parsed.build_cmd || parsed.verify)) {
|
|
23
23
|
return {
|
|
24
24
|
testCmd: parsed.verify?.test || parsed.test_cmd || "",
|
|
25
|
+
lintCmd: parsed.verify?.lint || parsed.lint_cmd || "",
|
|
26
|
+
fuzzCmd: parsed.verify?.fuzz || parsed.fuzz_cmd || "",
|
|
27
|
+
invariantCmd: parsed.verify?.invariant || parsed.invariant_cmd || "",
|
|
28
|
+
e2eCmd: parsed.verify?.e2e || parsed.e2e_cmd || "",
|
|
25
29
|
buildCmd: parsed.verify?.build || parsed.build_cmd || "",
|
|
30
|
+
policy: parsed.verify?.policy || { networkAccess: "allow", offline: false },
|
|
31
|
+
stages: parsed.verify?.stages || null,
|
|
26
32
|
source: configPath.endsWith("jules.yml") ? ".agent/jules.yml" : ".agent/config.yml",
|
|
27
33
|
};
|
|
28
34
|
}
|
|
@@ -50,8 +56,16 @@ export function detectFrameworkCommands(root = process.cwd()) {
|
|
|
50
56
|
const res = detectStack(root);
|
|
51
57
|
return {
|
|
52
58
|
testCmd: res.testCmd,
|
|
59
|
+
lintCmd: res.fmtCmd || "",
|
|
60
|
+
fuzzCmd: res.fuzzCmd || "",
|
|
61
|
+
invariantCmd: res.invariantCmd || "",
|
|
62
|
+
e2eCmd: res.e2eCmd || "",
|
|
53
63
|
buildCmd: res.buildCmd,
|
|
54
|
-
|
|
64
|
+
policy: {
|
|
65
|
+
networkAccess: res.stack === "foundry" ? "forbidden" : "allow",
|
|
66
|
+
offline: res.stack === "foundry",
|
|
67
|
+
},
|
|
68
|
+
source: `${res.triggerFile || "stack"} (${res.stack})`,
|
|
55
69
|
};
|
|
56
70
|
}
|
|
57
71
|
|
|
@@ -10,7 +10,7 @@ import { join } from "node:path";
|
|
|
10
10
|
import { tmpdir } from "node:os";
|
|
11
11
|
import { spawnSync } from "node:child_process";
|
|
12
12
|
import { classifyRiskTier, RISK_TIERS } from "../src/risk.mjs";
|
|
13
|
-
import {
|
|
13
|
+
import { git, resolveBase } from "../src/git.mjs";
|
|
14
14
|
import { normalizePath } from "../src/config.mjs";
|
|
15
15
|
|
|
16
16
|
export const EXIT = Object.freeze({
|
package/src/config.mjs
CHANGED
|
@@ -185,9 +185,23 @@ export function detectPackageManager(root = process.cwd(), pkg = {}) {
|
|
|
185
185
|
return "npm";
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
import {
|
|
189
|
-
|
|
190
|
-
|
|
188
|
+
import {
|
|
189
|
+
detectPolyglotStack,
|
|
190
|
+
resolveWorkspaceBoundary,
|
|
191
|
+
bootstrapZeroTestRepo,
|
|
192
|
+
findSubprojectRoot,
|
|
193
|
+
detectCrossPackageBoundaryViolations,
|
|
194
|
+
detectCircularDependencies,
|
|
195
|
+
} from "./stack-detector.mjs";
|
|
196
|
+
|
|
197
|
+
export {
|
|
198
|
+
detectPolyglotStack,
|
|
199
|
+
resolveWorkspaceBoundary,
|
|
200
|
+
bootstrapZeroTestRepo,
|
|
201
|
+
findSubprojectRoot,
|
|
202
|
+
detectCrossPackageBoundaryViolations,
|
|
203
|
+
detectCircularDependencies,
|
|
204
|
+
};
|
|
191
205
|
|
|
192
206
|
/**
|
|
193
207
|
* Autodetects verification test/build commands across 24+ polyglot tech stacks.
|
|
@@ -200,9 +214,19 @@ export function resolveVerify(root = process.cwd(), userVerify = {}) {
|
|
|
200
214
|
const s = detectStack(root);
|
|
201
215
|
return {
|
|
202
216
|
setup: userVerify.setup ?? s.setupCmd ?? "",
|
|
217
|
+
lint: userVerify.lint ?? s.fmtCmd ?? "",
|
|
203
218
|
test: userVerify.test ?? s.testCmd ?? "",
|
|
219
|
+
unit: userVerify.unit ?? userVerify.test ?? s.testCmd ?? "",
|
|
220
|
+
fuzz: userVerify.fuzz ?? s.fuzzCmd ?? "",
|
|
221
|
+
invariant: userVerify.invariant ?? s.invariantCmd ?? "",
|
|
222
|
+
e2e: userVerify.e2e ?? s.e2eCmd ?? "",
|
|
204
223
|
teardown: userVerify.teardown ?? s.teardownCmd ?? "",
|
|
205
224
|
build: userVerify.build ?? s.buildCmd ?? "",
|
|
225
|
+
policy: {
|
|
226
|
+
networkAccess: userVerify.policy?.networkAccess || (s.stack === "foundry" ? "forbidden" : "allow"),
|
|
227
|
+
offline: userVerify.policy?.offline ?? (s.stack === "foundry"),
|
|
228
|
+
},
|
|
229
|
+
stages: Array.isArray(userVerify.stages) ? userVerify.stages : null,
|
|
206
230
|
server: userVerify.server ? {
|
|
207
231
|
command: userVerify.server.command || "",
|
|
208
232
|
url: userVerify.server.url || "http://localhost:3000",
|
|
@@ -259,6 +283,10 @@ export function loadConfig(root = resolveRoot(), explicitPath = null) {
|
|
|
259
283
|
|
|
260
284
|
const setupCmd = parsed.setup_cmd || parsed.verify?.setup || "";
|
|
261
285
|
const testCmd = parsed.test_cmd || parsed.verify?.test || "";
|
|
286
|
+
const lintCmd = parsed.lint_cmd || parsed.verify?.lint || "";
|
|
287
|
+
const fuzzCmd = parsed.fuzz_cmd || parsed.verify?.fuzz || "";
|
|
288
|
+
const invariantCmd = parsed.invariant_cmd || parsed.verify?.invariant || "";
|
|
289
|
+
const e2eCmd = parsed.e2e_cmd || parsed.verify?.e2e || "";
|
|
262
290
|
const teardownCmd = parsed.teardown_cmd || parsed.verify?.teardown || "";
|
|
263
291
|
const buildCmd = parsed.build_cmd || parsed.verify?.build || "";
|
|
264
292
|
const verifyTimeoutMs = parsed.verify?.timeoutMs ?? parsed.verify?.timeout_ms ?? 60000;
|
|
@@ -289,11 +317,28 @@ export function loadConfig(root = resolveRoot(), explicitPath = null) {
|
|
|
289
317
|
tier: activeTier,
|
|
290
318
|
verify: {
|
|
291
319
|
setup: setupCmd || autoVerify.setup || "",
|
|
320
|
+
lint: lintCmd || autoVerify.lint || "",
|
|
292
321
|
test: testCmd || autoVerify.test,
|
|
322
|
+
unit: parsed.verify?.unit || testCmd || autoVerify.unit || autoVerify.test,
|
|
323
|
+
fuzz: fuzzCmd || autoVerify.fuzz || "",
|
|
324
|
+
invariant: invariantCmd || autoVerify.invariant || "",
|
|
325
|
+
e2e: e2eCmd || autoVerify.e2e || "",
|
|
293
326
|
teardown: teardownCmd || autoVerify.teardown || "",
|
|
294
327
|
build: buildCmd || autoVerify.build,
|
|
328
|
+
stages: parsed.verify?.stages || autoVerify.stages || null,
|
|
329
|
+
policy: parsed.verify?.policy || autoVerify.policy,
|
|
295
330
|
timeoutMs: Number.isFinite(Number(verifyTimeoutMs)) ? Number(verifyTimeoutMs) : 60000,
|
|
296
331
|
},
|
|
332
|
+
evidence: {
|
|
333
|
+
enabled: parsed.evidence?.enabled ?? true,
|
|
334
|
+
strictTestLock: parsed.evidence?.strict_test_lock ?? parsed.evidence?.strictTestLock ?? true,
|
|
335
|
+
},
|
|
336
|
+
router: {
|
|
337
|
+
enabled: parsed.router?.enabled ?? false,
|
|
338
|
+
fast: parsed.router?.fast || "gemini-flash",
|
|
339
|
+
complex: parsed.router?.complex || "",
|
|
340
|
+
threshold: Number.isFinite(Number(parsed.router?.threshold)) ? Number(parsed.router.threshold) : 0,
|
|
341
|
+
},
|
|
297
342
|
scope: normalizeScope(parsed),
|
|
298
343
|
limits: {
|
|
299
344
|
...DEFAULTS.limits,
|