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 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 **706 unit tests across 85 suites passing in < 10.0s**.
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 gate --mode working-tree [--fix] [--json] [--json-report <path>]` | Runs security, secret scanning, and tiered verification gates (with declarative assertion support) against working tree or branch. Secret findings name the file and line; a failed verify stage reports its command, exit code and output. | `0` (Approved), `3` (Scope), `4` (Verify), `5` (Diff >75K), `6` (Secret), `8` (Flaky) |
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.41.1",
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");