jules-orchestrator-kit 0.41.1 ā 0.42.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/README.md +3 -2
- package/bin/agentctl.mjs +73 -0
- package/package.json +1 -1
- package/src/scaffold.mjs +138 -1
package/README.md
CHANGED
|
@@ -143,7 +143,7 @@ To maximize PR merge rates, dispatch tasks according to deterministic boundaries
|
|
|
143
143
|
* **Fail-Closed Security & Secret Redaction:** Evaluates explicit Deny rules before Allow rules against canonicalized, case-folded paths. Redacts high-entropy keys and base64-encoded credentials (such as Kubernetes `Secret` manifests).
|
|
144
144
|
* **Complexity & Cost Router:** Zero-dependency heuristic classifier (`src/router.mjs`) routing mechanical tasks to lightweight models while reserving primary models for complex refactors, with a `node --check` syntax-verification gate that transparently escalates a FAST-tier result to the primary provider if it left broken JS on disk.
|
|
145
145
|
* **Terminal UI & Diagnostic Matrix (`agentctl doctor`):** Interactive terminal dashboard, task sidecar manager, and automated transactional self-repair.
|
|
146
|
-
* **Verified Test Suite:** Tested with **
|
|
146
|
+
* **Verified Test Suite:** Tested with **717 unit tests across 85 suites passing in < 10.0s**.
|
|
147
147
|
|
|
148
148
|
<br/>
|
|
149
149
|
|
|
@@ -169,7 +169,8 @@ To maximize PR merge rates, dispatch tasks according to deterministic boundaries
|
|
|
169
169
|
| `doctor` | `agentctl doctor [--json]` | Diagnostic DAG check runner & automated transactional self-repair engine. | `0` (Healthy), `1` (Failures) |
|
|
170
170
|
| `queue` | `agentctl queue [--dag] [--concurrency <n>] [--dry-run] [--json]` | Consumes and executes task envelopes in `.agent/jules-queue/` with Kahn's DAG dependency resolution. Non-task files (manifests, `README.md`) are skipped, and `--dry-run` previews without moving anything. | `0` (Complete) |
|
|
171
171
|
| `swarm` | `agentctl swarm [--json]` | Runs parallel multi-agent swarm across worker slots with PID liveness detection. | `0` (Complete) |
|
|
172
|
-
| `gate` / `audit`| `agentctl
|
|
172
|
+
| `check` / `gate` / `audit`| `agentctl check [--mode working-tree] [--fix] [--json] [--json-report <path>]` | Runs security, secret scanning, rules budget audit, and tiered verification gates (with declarative assertion support) against working tree or branch. | `0` (Approved), `1` (Budget/Arg), `3` (Scope), `4` (Verify), `5` (Diff >75K), `6` (Secret), `8` (Flaky) |
|
|
173
|
+
| `rules` | `agentctl rules <check\|compile> [--out <path>] [--json]` | Audits instruction files against character/line budgets or compiles unified rules block with SHA-256 and length anti-truncation sentinels. | `0` (Valid/Compiled), `1` (Violations) |
|
|
173
174
|
| `assert` | `agentctl assert [--dir <d>] [--file <f>] [--max-mb <n>] [--gzip] [--targets <g>] [--patterns <p>] [--json] [--json-report <p>]` | Runs declarative zero-dependency verification assertion primitives (`assert:dir-size`, `assert:file-size`, `assert:file-patterns`, `assert:exists`). | `0` (Passed), `1` (Assertion Failed) |
|
|
174
175
|
| `rollback` | `agentctl rollback [sessionId \| --latest]` | Restores exact commit, uncommitted files, and cleans orphan task worktrees from pre-flight checkpoints. | `0` (Restored), `1` (Error) |
|
|
175
176
|
| `resume` | `agentctl resume <sessionId> --response "<reply>"` | Streams engineer response back into active Google Jules warm session context window. | `0` (Resumed), `1` (Error) |
|
package/bin/agentctl.mjs
CHANGED
|
@@ -41,7 +41,9 @@ Usage: agentctl <command> [options]
|
|
|
41
41
|
|
|
42
42
|
Commands:
|
|
43
43
|
dispatch | create Dispatch a single task to an AI agent (--role <name>, --tier fast|complex, --check-premise)
|
|
44
|
+
check Run all-in-one CI security, rules, and stack verification gate
|
|
44
45
|
gate | audit Run CI security and verification gate against current branch
|
|
46
|
+
rules <action> Audit rule token budgets or compile rule sentinels (check | compile)
|
|
45
47
|
queue Run pending task queue (--dag, --concurrency <n>)
|
|
46
48
|
swarm Run parallel task swarm
|
|
47
49
|
mcp Start stdio Model Context Protocol (MCP) server
|
|
@@ -343,6 +345,7 @@ async function main() {
|
|
|
343
345
|
break;
|
|
344
346
|
}
|
|
345
347
|
|
|
348
|
+
case "check":
|
|
346
349
|
case "gate":
|
|
347
350
|
case "audit": {
|
|
348
351
|
const { values } = parseArgs({
|
|
@@ -1888,6 +1891,76 @@ async function main() {
|
|
|
1888
1891
|
break;
|
|
1889
1892
|
}
|
|
1890
1893
|
|
|
1894
|
+
case "rules": {
|
|
1895
|
+
const subcmd = args[1] || "check";
|
|
1896
|
+
const { checkRulesBudget, compileRules } = await import("../src/rules_budget.mjs");
|
|
1897
|
+
|
|
1898
|
+
if (subcmd === "check") {
|
|
1899
|
+
const { values } = parseArgs({
|
|
1900
|
+
args: args.slice(2),
|
|
1901
|
+
options: {
|
|
1902
|
+
json: { type: "boolean", short: "j" },
|
|
1903
|
+
"max-chars": { type: "string" },
|
|
1904
|
+
"max-lines": { type: "string" },
|
|
1905
|
+
},
|
|
1906
|
+
allowPositionals: true,
|
|
1907
|
+
});
|
|
1908
|
+
|
|
1909
|
+
const res = checkRulesBudget(root, {
|
|
1910
|
+
maxChars: values["max-chars"] ? Number(values["max-chars"]) : undefined,
|
|
1911
|
+
maxLines: values["max-lines"] ? Number(values["max-lines"]) : undefined,
|
|
1912
|
+
});
|
|
1913
|
+
|
|
1914
|
+
if (values.json) {
|
|
1915
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1916
|
+
} else {
|
|
1917
|
+
console.log("\nš agentctl Rules Budget & Line Audit");
|
|
1918
|
+
console.log("-----------------------------------------------------");
|
|
1919
|
+
if (res.ok) {
|
|
1920
|
+
console.log("ā
All agent rule files are within safe character (<10,000) and line (<250) limits.");
|
|
1921
|
+
} else {
|
|
1922
|
+
console.log("ā RULES BUDGET VIOLATIONS DETECTED:");
|
|
1923
|
+
for (const v of res.violations) {
|
|
1924
|
+
console.log(` - ${v.path}: ${v.reason}`);
|
|
1925
|
+
}
|
|
1926
|
+
console.log("\nš” Remediation: Trim prose rules or convert textual learnings into AST lints / assertions.");
|
|
1927
|
+
}
|
|
1928
|
+
console.log("-----------------------------------------------------\n");
|
|
1929
|
+
}
|
|
1930
|
+
process.exit(res.ok ? 0 : 1);
|
|
1931
|
+
} else if (subcmd === "compile") {
|
|
1932
|
+
const { values } = parseArgs({
|
|
1933
|
+
args: args.slice(2),
|
|
1934
|
+
options: {
|
|
1935
|
+
out: { type: "string", short: "o" },
|
|
1936
|
+
json: { type: "boolean", short: "j" },
|
|
1937
|
+
},
|
|
1938
|
+
allowPositionals: true,
|
|
1939
|
+
});
|
|
1940
|
+
|
|
1941
|
+
const res = compileRules(root);
|
|
1942
|
+
if (values.out) {
|
|
1943
|
+
const { writeFileSync } = await import("node:fs");
|
|
1944
|
+
const { resolve } = await import("node:path");
|
|
1945
|
+
writeFileSync(resolve(root, values.out), res.compiled, "utf-8");
|
|
1946
|
+
if (values.json) {
|
|
1947
|
+
console.log(JSON.stringify({ ok: true, out: values.out, sha256: res.sha256, bodyLen: res.bodyLen, sources: res.sources }, null, 2));
|
|
1948
|
+
} else {
|
|
1949
|
+
console.log(`ā
Compiled ${res.sources.length} rule source(s) into ${values.out} (SHA-256: ${res.sha256.slice(0, 12)}..., ${res.bodyLen} bytes)`);
|
|
1950
|
+
}
|
|
1951
|
+
} else if (values.json) {
|
|
1952
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1953
|
+
} else {
|
|
1954
|
+
console.log(res.compiled);
|
|
1955
|
+
}
|
|
1956
|
+
process.exit(0);
|
|
1957
|
+
} else {
|
|
1958
|
+
console.error(`Unknown rules action: "${subcmd}". Usage: agentctl rules [check | compile]`);
|
|
1959
|
+
process.exit(1);
|
|
1960
|
+
}
|
|
1961
|
+
break;
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1891
1964
|
default:
|
|
1892
1965
|
console.error(`Unknown command: ${command}`);
|
|
1893
1966
|
printHelp();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jules-orchestrator-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.0",
|
|
4
4
|
"description": "Zero-dependency safety gatekeeper, test oracle generator, and multi-agent coordination protocol for Google Jules (jules) autonomous agents.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
package/src/scaffold.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readdirSync, copyFileSync, readFileSync, appendFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join, dirname } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { detectPolyglotStack, detectEdgeRuntime } from "./stack-detector.mjs";
|
|
4
5
|
|
|
5
6
|
const KIT_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
6
7
|
|
|
@@ -77,6 +78,136 @@ function copyDir(srcDir, destDir, force) {
|
|
|
77
78
|
return written;
|
|
78
79
|
}
|
|
79
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Generate stack-tailored contract templates (SPEC.md, CONSTRAINTS.md, DESIGN.md).
|
|
83
|
+
*
|
|
84
|
+
* @param {string} root - Project root
|
|
85
|
+
* @param {{ force?: boolean }} [options]
|
|
86
|
+
* @returns {string[]} Created contract file names
|
|
87
|
+
*/
|
|
88
|
+
export function scaffoldContracts(root = process.cwd(), options = {}) {
|
|
89
|
+
const force = Boolean(options.force);
|
|
90
|
+
const created = [];
|
|
91
|
+
|
|
92
|
+
const specPath = join(root, "SPEC.md");
|
|
93
|
+
if (!existsSync(specPath) || force) {
|
|
94
|
+
const specContent = `# SPEC ā System & Product Contract
|
|
95
|
+
|
|
96
|
+
## Product
|
|
97
|
+
- Brief 1ā2 sentence description of the system and target users.
|
|
98
|
+
|
|
99
|
+
## Core Loop
|
|
100
|
+
- Step-by-step lifecycle from input/event to final response/artifact.
|
|
101
|
+
|
|
102
|
+
## Goals
|
|
103
|
+
- [Goal 1: Core invariant functionality that MUST work]
|
|
104
|
+
- [Goal 2: Performance, throughput, or latency targets]
|
|
105
|
+
- [Goal 3: Test coverage & reliability criteria]
|
|
106
|
+
|
|
107
|
+
## Non-Goals
|
|
108
|
+
- [Explicit out-of-scope feature or abstraction]
|
|
109
|
+
- [Out-of-scope third-party dependencies or integrations]
|
|
110
|
+
|
|
111
|
+
## Definition of Done
|
|
112
|
+
- All verification test suites pass cleanly with 0 errors
|
|
113
|
+
- Zero security vulnerabilities and zero leaked secrets
|
|
114
|
+
- Diff size stays within the configured limit (<= 75 KB)
|
|
115
|
+
`;
|
|
116
|
+
writeFileSync(specPath, specContent, "utf-8");
|
|
117
|
+
created.push("SPEC.md");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const constraintsPath = join(root, "CONSTRAINTS.md");
|
|
121
|
+
if (!existsSync(constraintsPath) || force) {
|
|
122
|
+
const edgeInfo = detectEdgeRuntime(root);
|
|
123
|
+
const stackInfo = detectPolyglotStack(root);
|
|
124
|
+
|
|
125
|
+
let constraintsContent = "";
|
|
126
|
+
if (edgeInfo.edgePlatform === "cloudflare") {
|
|
127
|
+
constraintsContent = `# CONSTRAINTS ā Cloudflare Workers / workerd
|
|
128
|
+
|
|
129
|
+
## Runtime Invariants
|
|
130
|
+
- Zero unbundled \`node:*\` imports in \`src/\` (rely on standard Web APIs or polyfilled modules)
|
|
131
|
+
- Bundle size: Max 10 MB total
|
|
132
|
+
- RAM memory limit: 128 MB
|
|
133
|
+
- Database & KV: Batch operations via \`db.batch([])\`, zero unbounded query loops
|
|
134
|
+
- Static content: Zero client-side JavaScript for static content
|
|
135
|
+
`;
|
|
136
|
+
} else if (stackInfo.stack === "cargo") {
|
|
137
|
+
constraintsContent = `# CONSTRAINTS ā Rust Architecture
|
|
138
|
+
|
|
139
|
+
## Runtime & Safety Invariants
|
|
140
|
+
- Zero \`unsafe\` blocks unless explicitly audited and documented
|
|
141
|
+
- No unhandled \`.unwrap()\` or \`.expect()\` in production/request-handling code paths
|
|
142
|
+
- Clippy compliance: \`cargo clippy -- -D warnings\` must pass with 0 warnings
|
|
143
|
+
- Strict error propagation using \`Result<T, E>\` / \`thiserror\` / \`anyhow\`
|
|
144
|
+
`;
|
|
145
|
+
} else if (stackInfo.stack === "go") {
|
|
146
|
+
constraintsContent = `# CONSTRAINTS ā Go Architecture
|
|
147
|
+
|
|
148
|
+
## Runtime & Safety Invariants
|
|
149
|
+
- Deterministic builds: \`CGO_ENABLED=0\`
|
|
150
|
+
- Explicit error handling: Never discard \`err\` returns (\`_ = err\` is strictly prohibited)
|
|
151
|
+
- Data race free: \`go test -race ./...\` must pass with 0 failures
|
|
152
|
+
- Strict struct tagging and deterministic serialization
|
|
153
|
+
`;
|
|
154
|
+
} else if (["python", "poetry", "uv", "pipenv"].includes(stackInfo.stack)) {
|
|
155
|
+
constraintsContent = `# CONSTRAINTS ā Python Architecture
|
|
156
|
+
|
|
157
|
+
## Runtime & Safety Invariants
|
|
158
|
+
- Strict type annotations on all function signatures (\`mypy --strict\` passes)
|
|
159
|
+
- Zero unpinned dependencies in production manifests
|
|
160
|
+
- Lint & format cleanly with \`ruff\` or \`flake8\`/\`black\`
|
|
161
|
+
- Pytest suite passes 100% cleanly
|
|
162
|
+
`;
|
|
163
|
+
} else {
|
|
164
|
+
constraintsContent = `# CONSTRAINTS ā Technical Invariants
|
|
165
|
+
|
|
166
|
+
## Architecture & Code Quality
|
|
167
|
+
- Zero third-party runtime dependencies in core orchestration/shared packages
|
|
168
|
+
- Diff Payload Budget: Keep diffs under 75 KB to prevent truncation
|
|
169
|
+
- Strict Test Lock: Never weaken assertions or delete failing tests to force green status
|
|
170
|
+
- Cross-Platform: Normalize all filesystem paths to POSIX slashes (\`/\`)
|
|
171
|
+
`;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
writeFileSync(constraintsPath, constraintsContent, "utf-8");
|
|
175
|
+
created.push("CONSTRAINTS.md");
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// If web/UI stack is detected (Astro, Next, Svelte, Vue, React, Tailwind), scaffold DESIGN.md
|
|
179
|
+
const isWeb = existsSync(join(root, "astro.config.mjs")) ||
|
|
180
|
+
existsSync(join(root, "next.config.js")) ||
|
|
181
|
+
existsSync(join(root, "next.config.mjs")) ||
|
|
182
|
+
existsSync(join(root, "svelte.config.js")) ||
|
|
183
|
+
existsSync(join(root, "tailwind.config.js")) ||
|
|
184
|
+
existsSync(join(root, "tailwind.config.mjs")) ||
|
|
185
|
+
existsSync(join(root, "tailwind.config.ts"));
|
|
186
|
+
|
|
187
|
+
const designPath = join(root, "DESIGN.md");
|
|
188
|
+
if (isWeb && (!existsSync(designPath) || force)) {
|
|
189
|
+
const designContent = `# DESIGN ā Visual Tokens & Design System
|
|
190
|
+
|
|
191
|
+
## Typography
|
|
192
|
+
- Headings: Clean sans-serif / geometric font
|
|
193
|
+
- Body: Readable system font / sans-serif
|
|
194
|
+
|
|
195
|
+
## Tokens (@theme)
|
|
196
|
+
- Consistent spacing scale (4px, 8px, 16px, 24px, 32px, 48px)
|
|
197
|
+
- Strict color tokens for surfaces, text, and borders
|
|
198
|
+
|
|
199
|
+
## Hard UI Rules
|
|
200
|
+
- Zero client-side JS for purely static content
|
|
201
|
+
- Accessible contrast ratios (WCAG AA minimum 4.5:1)
|
|
202
|
+
- Explicit hover, focus-visible, and active states on all interactive elements
|
|
203
|
+
`;
|
|
204
|
+
writeFileSync(designPath, designContent, "utf-8");
|
|
205
|
+
created.push("DESIGN.md");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return created;
|
|
209
|
+
}
|
|
210
|
+
|
|
80
211
|
/**
|
|
81
212
|
* Scaffold the repository assets the CLI's documented features depend on.
|
|
82
213
|
*
|
|
@@ -90,7 +221,7 @@ function copyDir(srcDir, destDir, force) {
|
|
|
90
221
|
* routine way to pick up new presets and must not overwrite local edits.
|
|
91
222
|
*
|
|
92
223
|
* @param {string} [root=process.cwd()]
|
|
93
|
-
* @param {{ force?: boolean }} [options]
|
|
224
|
+
* @param {{ force?: boolean, contracts?: boolean }} [options]
|
|
94
225
|
* @returns {{ created: string[], gitignore: string[] }}
|
|
95
226
|
*/
|
|
96
227
|
export function scaffoldRepoAssets(root = process.cwd(), options = {}) {
|
|
@@ -128,6 +259,12 @@ export function scaffoldRepoAssets(root = process.cwd(), options = {}) {
|
|
|
128
259
|
created.push(".agent/workflows/");
|
|
129
260
|
}
|
|
130
261
|
|
|
262
|
+
// Scaffold contract documents (SPEC.md, CONSTRAINTS.md, DESIGN.md)
|
|
263
|
+
if (options.contracts !== false) {
|
|
264
|
+
const contracts = scaffoldContracts(root, options);
|
|
265
|
+
created.push(...contracts);
|
|
266
|
+
}
|
|
267
|
+
|
|
131
268
|
// isTaskFile() skips README.md, so the queue can carry its own explanation
|
|
132
269
|
// without the runner mistaking it for a task envelope.
|
|
133
270
|
const queueReadme = join(queueDir, "README.md");
|