jules-orchestrator-kit 0.75.1 → 0.75.2
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/CHANGELOG.md +14 -0
- package/README.md +2 -2
- package/bin/agentctl.mjs +29 -21
- package/package.json +2 -2
- package/src/ci-templates.mjs +1 -0
- package/src/engine.mjs +9 -3
- package/src/envelope.mjs +17 -1
- package/src/ops/command-registry.mjs +2 -1
- package/src/ops/tui-menu.mjs +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.75.2] - 2026-10-09
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Committed Mode Snapshot Target (`src/engine.mjs`)**: Pointed `materializeSnapshot` to target commit `opts.head` (defaults to `HEAD`) instead of base commit when evaluating in committed mode.
|
|
14
|
+
- **Auto-Merge CI PR Head Checkout (`src/ci-templates.mjs`)**: Detached checkout to fetched PR head (`git checkout --detach refs/pr-head`) before gate evaluation so PR verification tests candidate changes rather than base.
|
|
15
|
+
- **TUI Interactive Fallback on Headless CI (`src/ops/tui-menu.mjs`)**: Allowed interactive terminal UI menu execution when custom mock streams are explicitly provided even if `process.env.CI` is defined.
|
|
16
|
+
- **Pure JSON Output in Task Queue (`bin/agentctl.mjs`)**: Suppressed decorative informational messages during `agentctl queue --json` execution for uncorrupted machine consumption.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- **CLI Navigation Aliases & Gate Flags (`bin/agentctl.mjs`, `src/ops/command-registry.mjs`)**: Added `hub` alias for `menu`, `task new` alias for `task create`, and forwarded `--head` to `agentctl check` and verification gate.
|
|
20
|
+
|
|
21
|
+
### Security
|
|
22
|
+
- **Task Envelope & Pre-Dispatch Secret Prevention (`src/envelope.mjs`, `src/engine.mjs`)**: Rejected prompts and task intents containing unredacted high-confidence credentials before queuing or agent dispatch.
|
|
23
|
+
|
|
10
24
|
## [0.75.1] - 2026-10-09
|
|
11
25
|
|
|
12
26
|
### Added
|
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ You can also run local checks without connecting an agent provider.
|
|
|
17
17
|
`agentctl repair` explicitly for repair workflows. Provider output and passing
|
|
18
18
|
checks still need review before merging.
|
|
19
19
|
|
|
20
|
-
The current release is **v0.75.
|
|
20
|
+
The current release is **v0.75.2**, a pre-1.0 release. A long-term stability policy is a
|
|
21
21
|
[v1.0 goal](https://github.com/FullThrottle83/jules-orchestrator-kit/blob/main/ROADMAP_V1.md).
|
|
22
22
|
|
|
23
23
|
## Quickstart
|
|
@@ -176,7 +176,7 @@ npm run package-integrity
|
|
|
176
176
|
npm run guard-reach
|
|
177
177
|
```
|
|
178
178
|
|
|
179
|
-
The recorded baseline is **
|
|
179
|
+
The recorded baseline is **1670 unit tests across 210 suites**. Doc-sync compares
|
|
180
180
|
that count with an actual run. Counts do not establish correctness for every
|
|
181
181
|
provider or project. See
|
|
182
182
|
[contributing](https://github.com/FullThrottle83/jules-orchestrator-kit/blob/main/CONTRIBUTING.md)
|
package/bin/agentctl.mjs
CHANGED
|
@@ -272,8 +272,8 @@ async function main() {
|
|
|
272
272
|
if (!command) {
|
|
273
273
|
if (args.includes("-i") || args.includes("--interactive")) {
|
|
274
274
|
const { runTuiMenu } = await import("../src/ops/tui-menu.mjs");
|
|
275
|
-
await runTuiMenu(resolveRoot());
|
|
276
|
-
process.exit(0);
|
|
275
|
+
const res = await runTuiMenu(resolveRoot());
|
|
276
|
+
process.exit(res?.code || (res?.headless ? 1 : 0));
|
|
277
277
|
}
|
|
278
278
|
const { resolveNextStep, renderNextStep } = await import("../src/ops/next-step.mjs");
|
|
279
279
|
const cwd = process.cwd();
|
|
@@ -497,6 +497,7 @@ async function main() {
|
|
|
497
497
|
args: args.slice(1),
|
|
498
498
|
options: {
|
|
499
499
|
base: { type: "string", short: "b" },
|
|
500
|
+
head: { type: "string" },
|
|
500
501
|
mode: { type: "string", short: "m", default: "working-tree" },
|
|
501
502
|
"working-tree": { type: "boolean" },
|
|
502
503
|
staged: { type: "boolean" },
|
|
@@ -532,6 +533,7 @@ async function main() {
|
|
|
532
533
|
root,
|
|
533
534
|
config,
|
|
534
535
|
base: values.base,
|
|
536
|
+
head: values.head,
|
|
535
537
|
mode: selectedMode,
|
|
536
538
|
fix: values.fix,
|
|
537
539
|
allowProtected: values["allow-protected"],
|
|
@@ -1402,24 +1404,29 @@ async function main() {
|
|
|
1402
1404
|
} else {
|
|
1403
1405
|
files = queueEntries.filter((f) => isTaskFile(f, queueDir));
|
|
1404
1406
|
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
root,
|
|
1410
|
-
config,
|
|
1411
|
-
dag: values.dag,
|
|
1412
|
-
concurrency,
|
|
1413
|
-
dryRun: values["dry-run"],
|
|
1414
|
-
});
|
|
1407
|
+
if (!values.json) {
|
|
1408
|
+
console.log(`Found ${files.length} queued task(s) in .agent/jules-queue/`);
|
|
1409
|
+
}
|
|
1410
|
+
if (files.length === 0) {
|
|
1415
1411
|
if (values.json) {
|
|
1416
|
-
console.log(JSON.stringify(results, null, 2));
|
|
1417
|
-
const anyFailed = (results.results || []).some((r) => r && r.ok === false);
|
|
1418
|
-
process.exit(anyFailed ? 1 : 0);
|
|
1412
|
+
console.log(JSON.stringify({ ok: true, processed: 0, results: [], dryRun: Boolean(values["dry-run"]) }, null, 2));
|
|
1419
1413
|
}
|
|
1420
|
-
process.exit(
|
|
1414
|
+
process.exit(0);
|
|
1421
1415
|
}
|
|
1422
|
-
|
|
1416
|
+
const concurrency = values.concurrency ? Number(values.concurrency) : undefined;
|
|
1417
|
+
const results = await run(null, {
|
|
1418
|
+
root,
|
|
1419
|
+
config,
|
|
1420
|
+
dag: values.dag,
|
|
1421
|
+
concurrency,
|
|
1422
|
+
dryRun: values["dry-run"],
|
|
1423
|
+
});
|
|
1424
|
+
if (values.json) {
|
|
1425
|
+
console.log(JSON.stringify(results, null, 2));
|
|
1426
|
+
const anyFailed = (results.results || []).some((r) => r && r.ok === false);
|
|
1427
|
+
process.exit(anyFailed ? 1 : 0);
|
|
1428
|
+
}
|
|
1429
|
+
process.exit(reportRunOutcome(results));
|
|
1423
1430
|
break;
|
|
1424
1431
|
}
|
|
1425
1432
|
|
|
@@ -2031,12 +2038,13 @@ async function main() {
|
|
|
2031
2038
|
break;
|
|
2032
2039
|
}
|
|
2033
2040
|
|
|
2041
|
+
case "hub":
|
|
2034
2042
|
case "menu":
|
|
2035
2043
|
case "tui":
|
|
2036
2044
|
case "ui": {
|
|
2037
2045
|
const { runTuiMenu } = await import("../src/ops/tui-menu.mjs");
|
|
2038
|
-
await runTuiMenu(root);
|
|
2039
|
-
process.exit(0);
|
|
2046
|
+
const res = await runTuiMenu(root);
|
|
2047
|
+
process.exit(res?.code || (res?.headless ? 1 : 0));
|
|
2040
2048
|
break;
|
|
2041
2049
|
}
|
|
2042
2050
|
|
|
@@ -2195,7 +2203,7 @@ async function main() {
|
|
|
2195
2203
|
|
|
2196
2204
|
case "task": {
|
|
2197
2205
|
const subCommand = args[1] || "create";
|
|
2198
|
-
if (subCommand === "create") {
|
|
2206
|
+
if (subCommand === "create" || subCommand === "new") {
|
|
2199
2207
|
const { values, positionals } = parseArgs({
|
|
2200
2208
|
args: args.slice(2),
|
|
2201
2209
|
options: {
|
|
@@ -2456,7 +2464,7 @@ async function main() {
|
|
|
2456
2464
|
|
|
2457
2465
|
process.exit(result.ok ? 0 : 1);
|
|
2458
2466
|
} else {
|
|
2459
|
-
console.error(`Unknown task subcommand '${subCommand}'. Supported: agentctl task create, agentctl task optimize, agentctl task template, agentctl task validate`);
|
|
2467
|
+
console.error(`Unknown task subcommand '${subCommand}'. Supported: agentctl task create (or task new), agentctl task optimize, agentctl task template, agentctl task validate`);
|
|
2460
2468
|
process.exit(1);
|
|
2461
2469
|
}
|
|
2462
2470
|
break;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jules-orchestrator-kit",
|
|
3
|
-
"version": "0.75.
|
|
4
|
-
"description": "Zero-dependency safety gatekeeper, test oracle generator, and multi-agent coordination protocol for autonomous coding agents
|
|
3
|
+
"version": "0.75.2",
|
|
4
|
+
"description": "Zero-dependency safety gatekeeper, test oracle generator, and multi-agent coordination protocol for autonomous coding agents — Google Jules, Claude Code, Codex and Gemini CLI.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/FullThrottle83/jules-orchestrator-kit.git"
|
package/src/ci-templates.mjs
CHANGED
package/src/engine.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { loadConfig, resolveTrustedPolicy, normalizePath } from "./config.mjs";
|
|
|
2
2
|
import { isTestPath } from "./test-paths.mjs";
|
|
3
3
|
import { isPlaceholderTestScript, isSrcLayout } from "./stack-detector.mjs";
|
|
4
4
|
import { checkCollectionFloor } from "./ops/test-collection.mjs";
|
|
5
|
-
import { checkScope, scanDiff, scanBinaryPayloads, redactSecrets } from "./security.mjs";
|
|
5
|
+
import { checkScope, scanDiff, scanBinaryPayloads, redactSecrets, hasHighConfidenceSecret } from "./security.mjs";
|
|
6
6
|
import { changedFiles, diffBytes, diffText, binaryDiffEntries, symlinkChanges, showFromOrigin, runCmd, materializeSnapshot } from "./git.mjs";
|
|
7
7
|
import { createProvider, ProviderRateLimitError, ProviderUnavailableError } from "./provider.mjs";
|
|
8
8
|
import { resolveRoutedProvider } from "./router.mjs";
|
|
@@ -306,7 +306,7 @@ export async function gate(opts = {}) {
|
|
|
306
306
|
let snapshot = { cwd: root, cleanup: () => {}, mode };
|
|
307
307
|
try {
|
|
308
308
|
if (mode === "staged" || mode === "committed") {
|
|
309
|
-
snapshot = materializeSnapshot(root, mode,
|
|
309
|
+
snapshot = materializeSnapshot(root, mode, opts.head || "HEAD");
|
|
310
310
|
}
|
|
311
311
|
} catch (snapErr) {
|
|
312
312
|
phases.push({ phase: "verify", ok: false, error: snapErr.message });
|
|
@@ -1482,8 +1482,14 @@ export async function dispatch(task = {}, opts = {}) {
|
|
|
1482
1482
|
};
|
|
1483
1483
|
}
|
|
1484
1484
|
|
|
1485
|
+
// Pre-dispatch secret leak prevention (unless explicitly allowed)
|
|
1486
|
+
const rawPrompt = task.prompt || "";
|
|
1487
|
+
if (!opts.allowSecrets && hasHighConfidenceSecret(rawPrompt)) {
|
|
1488
|
+
throw new Error("Pre-Dispatch Secret Leak Blocked: Task prompt contains unredacted high-confidence credentials.");
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1485
1491
|
// Redact secrets in prompt before dispatching
|
|
1486
|
-
let cleanPrompt = redactSecrets(
|
|
1492
|
+
let cleanPrompt = redactSecrets(rawPrompt);
|
|
1487
1493
|
|
|
1488
1494
|
// Specialist Role resolution (if role is set and not already present in prompt)
|
|
1489
1495
|
if (task.role) {
|
package/src/envelope.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { git, runCmd, resolveBase } from "./git.mjs";
|
|
2
|
-
import { checkScope } from "./security.mjs";
|
|
2
|
+
import { checkScope, scanDiff } from "./security.mjs";
|
|
3
3
|
import { normalizeScope } from "./config.mjs";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
5
|
import { resolve, relative, isAbsolute } from "node:path";
|
|
@@ -185,6 +185,22 @@ export function validateEnvelope(envelope = {}, opts = {}) {
|
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
// 11. Secret Leak Scrubbing Preflight
|
|
189
|
+
const textToScan = [
|
|
190
|
+
typeof envelope.prompt === "string" ? envelope.prompt : "",
|
|
191
|
+
typeof envelope.intent === "string" ? envelope.intent : (envelope.intent?.outcome || ""),
|
|
192
|
+
typeof envelope.instructions === "string" ? envelope.instructions : "",
|
|
193
|
+
].filter(Boolean).join("\n");
|
|
194
|
+
|
|
195
|
+
if (textToScan && !opts.allowSecrets) {
|
|
196
|
+
const multilineDiff = textToScan.split("\n").map((line) => `+${line}`).join("\n");
|
|
197
|
+
const secretScan = scanDiff(multilineDiff);
|
|
198
|
+
if (!secretScan.ok && secretScan.findings.length > 0) {
|
|
199
|
+
const types = secretScan.findings.map((f) => f.type || "SECRET_DETECTED").join(", ");
|
|
200
|
+
errors.push(`Secret leak detected in envelope prompt/intent (${types}). Scrub credentials before validation.`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
188
204
|
return {
|
|
189
205
|
ok: errors.length === 0,
|
|
190
206
|
code: errors.length === 0 ? 0 : 1,
|
|
@@ -373,9 +373,10 @@ export const COMMAND_REGISTRY = [
|
|
|
373
373
|
risk: "low",
|
|
374
374
|
interactive: "always",
|
|
375
375
|
requiresRepository: true,
|
|
376
|
-
shortcuts: ["tui", "ui"],
|
|
376
|
+
shortcuts: ["hub", "tui", "ui"],
|
|
377
377
|
examples: [
|
|
378
378
|
"agentctl menu",
|
|
379
|
+
"agentctl hub",
|
|
379
380
|
"agentctl tui",
|
|
380
381
|
],
|
|
381
382
|
flags: [],
|
package/src/ops/tui-menu.mjs
CHANGED
|
@@ -27,9 +27,11 @@ export async function runTuiMenu(root = process.cwd(), options = {}) {
|
|
|
27
27
|
const stdin = options.stdin || process.stdin;
|
|
28
28
|
const stdout = options.stdout || process.stdout;
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
const hasCustomStreams = Boolean(options.stdin || options.stdout);
|
|
31
|
+
const isInteractive = isTTY(stdin) && isTTY(stdout) && (!process.env.CI || hasCustomStreams || options.allowInteractive);
|
|
32
|
+
if (!isInteractive && !options.allowHeadless) {
|
|
31
33
|
stdout.write("Interactive terminal menu requires a TTY terminal. Use 'agentctl --help' for CLI commands.\n");
|
|
32
|
-
return { ok: true, headless: true };
|
|
34
|
+
return { ok: true, headless: true, code: 1 };
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
while (true) {
|