jules-orchestrator-kit 0.38.1 → 0.39.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.
@@ -32,7 +32,7 @@ To maximize the ratio of mergeable PRs vs. failed or hallucinated sessions:
32
32
  11. **Pre-Dispatch Grounding Mandate:** Verify all file paths, script names, and exported symbols against the live repository tree before writing them into a prompt.
33
33
  12. **Programmatic CI Scope Guarding:** Enforce prompt constraints at the CI level using an unbypassable `Agent Scope Guard` workflow that evaluates diffs against a protected paths manifest (`.agent/protected-paths.json`).
34
34
  13. **Google Labs Exploration Budget Protocol:** Execute tasks across 3 discrete phases: (1) Discovery & Symbol Tracing (silent inspection, write NO code), (2) Oracle & Test Formulation, and (3) Surgical Implementation & Verification.
35
- 14. **Critic Agent Steering (Adversarial Pre-Review):** Jules' internal Critic Agent must evaluate proposed patches for edge-case regressions, $O(n^2)$ bottlenecks, unhandled parameters, and layout shifts (CLS) prior to PR submission.
35
+ 14. **Critic Agent Steering (Adversarial Pre-Review):** Jules' internal Critic Agent must evaluate proposed patches for edge-case regressions, $O(n^2)$ bottlenecks, unhandled parameters, and layout shifts (CLS) prior to PR submission. When modifying test suites or error handling, the agent must deliberately mutate production code and induce real failure conditions to prove that tests and catch blocks actually fail as intended (preventing tautological tests).
36
36
  15. **Web Excellence & Frontend Guardrails:** Enforce quantitative Core Web Vitals (LCP < 1.2s, CLS < 0.05), WCAG 2.2 AA/AAA semantic accessibility, Schema.org JSON-LD compliance, and Playwright multi-viewport responsive testing.
37
37
  16. **Airtight Positive Enclosures ("Pink Elephant" Rule):** Replace long negative constraint lists with strict positive operational perimeters (`ONLY modify [Target/Module]`) to prevent attention-drift in deep context windows.
38
38
  17. **Sterile / Clinical Vocabulary Mandate:** Eradicate aggressive verbs (`kill`, `amputate`, `sabotage`, `destroy`) from prompts and policies. Use clinical equivalents (`terminate PID`, `prune code`, `mutate test logic`, `purge cache`) to prevent false-positive safety classifier trips in Google Cloud VMs.
@@ -58,7 +58,7 @@ Jules automatically infers test and build verification commands via `scripts/com
58
58
  - **Minimal Interference**: Preserve existing function signatures, comments, and style conventions.
59
59
  - **No Token Bloat**: Exclude lockfiles, minified bundles, and binary assets from diff representations.
60
60
  - **Google Labs Exploration Budget Protocol**: Execute complex multi-step tasks across 3 discrete phases: (1) Discovery & Symbol Tracing (silent inspection, write NO code), (2) Oracle & Test Formulation, and (3) Surgical Implementation & Verification.
61
- - **Critic Agent Steering (Adversarial Pre-Review)**: Jules' internal Critic Agent evaluates proposed patches for edge-case regressions, $O(n^2)$ bottlenecks, unhandled parameters, and layout shifts (CLS) prior to final PR submission.
61
+ - **Critic Agent Steering (Adversarial Pre-Review)**: Jules' internal Critic Agent evaluates proposed patches for edge-case regressions, $O(n^2)$ bottlenecks, unhandled parameters, and layout shifts (CLS) prior to final PR submission. In test modifications, verify deliberate logic mutations turn tests red (mutation falsification).
62
62
  - **Airtight Positive Enclosures ("Pink Elephant" Principle)**: Avoid massive negative constraint lists; define explicit positive perimeters (`ONLY modify [Target/Module]`) to eliminate attention distortion and cognitive drag.
63
63
  - **Sterile / Clinical Vocabulary Mandate**: Replace aggressive verbs (`kill`, `amputate`, `destroy`) with clinical equivalents (`terminate PID`, `prune code`, `purge state`) to prevent false-positive safety classifier tripwires.
64
64
 
package/README.md CHANGED
@@ -131,7 +131,7 @@ To maximize PR merge rates, dispatch tasks according to deterministic boundaries
131
131
  * **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).
132
132
  * **Complexity & Cost Router:** Zero-dependency heuristic classifier (`src/router.mjs`) routing mechanical tasks to lightweight models while reserving primary models for complex refactors.
133
133
  * **Terminal UI & Diagnostic Matrix (`agentctl doctor`):** Interactive terminal dashboard, task sidecar manager, and automated transactional self-repair.
134
- * **Verified Test Suite:** Tested with **569 unit tests across 81 suites passing in < 10.0s**.
134
+ * **Verified Test Suite:** Tested with **602 unit tests across 83 suites passing in < 10.0s**.
135
135
 
136
136
  <br/>
137
137
 
@@ -148,12 +148,16 @@ To maximize PR merge rates, dispatch tasks according to deterministic boundaries
148
148
  | :--- | :--- | :--- | :--- |
149
149
  | `init` | `agentctl init [--interactive] [--tier pro]` | Interactive onboarding wizard & stack detector generating `.agent/config.yml`. | `0` (Created) |
150
150
  | `task create` | `agentctl task create [--title <t>] [--prompt <p>] [--template <id>] [--role <name>] [--tier fast\|complex]` | Interactively authors & scopes falsifiable task envelopes with secret scrubbing, preflight gate checks, and DAG dependency wiring. | `0` (Queued), `1` (Secret/Unfalsifiable) |
151
- | `task template` | `agentctl task template [<id>] [--list] [--json]` | Lists and synthesizes pre-calibrated web task envelopes (`web-cwv`, `web-wcag`, `web-seo`, `web-playwright`, `web-flaky-heal`, `web-i18n`, `web-ai-access`). | `0` (Listed/Synthesized) |
152
- | `dispatch` | `agentctl dispatch [-p <prompt>] [-f <file>] [-r <role>] [-t <tier>] [--auto-pr] [--repoless] [--dry-run]` | Dispatches autonomous task to the active provider with payload limits and role prompt resolution. | `0` (Dispatched), `1` (Error) |
151
+ | `task template` | `agentctl task template [<id>] [--list] [--json]` | Lists and synthesizes pre-calibrated task envelopes (Web & Agent Hardening: `web-cwv`, `web-wcag`, `web-seo`, `web-playwright`, `agent-dead-code-audit`, `web-flaky-heal`, `web-i18n`, `web-ai-access`, `agent-qa-mutation`, `agent-ci-falsify`, `agent-service-isolate`, `agent-error-paths`, `agent-security-audit`). | `0` (Listed/Synthesized) |
152
+ | `dispatch` | `agentctl dispatch [-p <prompt>] [-f <file>] [-r <role>] [-t <tier>] [--check-premise] [--auto-pr] [--repoless] [--dry-run]` | Dispatches autonomous task to the active provider with pre-flight idempotency checks, payload limits, and role prompt resolution. | `0` (Dispatched), `1` (Error) |
153
+ | `plan approve` | `agentctl plan approve <sessionId> [--dry-run] [--json]` | Approves pending execution plan for an active Jules session (`:approvePlan`) with automatic 404/503 retry backoff. | `0` (Approved), `1` (Error) |
154
+ | `session get` | `agentctl session get <sessionId> [--dry-run] [--json]` | Retrieves live session lifecycle state from provider REST API with token rotation. | `0` (Fetched), `1` (Error) |
155
+ | `pr harvest` | `agentctl pr harvest [--tier r0,r1] [--limit <n>] [--auto] [--dry-run]` | Discovers open agent PRs, evaluates CI checks & risk tiers, and auto-squashes green low-risk changes autonomously. | `0` (Triaged/Merged), `1` (Error) |
153
156
  | `doctor` | `agentctl doctor [--json]` | Diagnostic DAG check runner & automated transactional self-repair engine. | `0` (Healthy), `1` (Failures) |
154
- | `queue` | `agentctl queue [--dag] [--concurrency <n>] [--dry-run] [--json]` | Consumes and executes task envelopes in `.agent/jules-queue/` with Kahn's DAG dependency resolution. | `0` (Complete) |
157
+ | `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) |
155
158
  | `swarm` | `agentctl swarm [--json]` | Runs parallel multi-agent swarm across worker slots with PID liveness detection. | `0` (Complete) |
156
- | `gate` / `audit`| `agentctl gate --mode working-tree [--json]` | Runs security, secret scanning, and verification gates against working tree or branch. | `0` (Approved), `3` (Scope), `5` (Diff >75K), `6` (Secret) |
159
+ | `gate` / `audit`| `agentctl gate --mode working-tree [--json] [--json-report <path>]` | Runs security, secret scanning, and tiered verification gates (with declarative assertion support) against working tree or branch. | `0` (Approved), `3` (Scope), `5` (Diff >75K), `6` (Secret) |
160
+ | `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) |
157
161
  | `rollback` | `agentctl rollback [sessionId \| --latest]` | Restores exact commit, uncommitted files, and cleans orphan task worktrees from pre-flight checkpoints. | `0` (Restored), `1` (Error) |
158
162
  | `resume` | `agentctl resume <sessionId> --response "<reply>"` | Streams engineer response back into active Google Jules warm session context window. | `0` (Resumed), `1` (Error) |
159
163
  | `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) |
@@ -319,6 +323,7 @@ console.log(classification.tier); // "fast" | "complex"
319
323
 
320
324
  | Feature | Module / Command | Architectural Description | Status |
321
325
  | :--- | :--- | :--- | :---: |
326
+ | **Queue Runner Fidelity** | `src/dag-engine.mjs`, `src/engine.mjs` | Queue selection is by task shape rather than file extension, so manifests and READMEs are skipped instead of dispatched, and `--dry-run` leaves the queue untouched. | **v0.38.2** *(Shipped)* |
322
327
  | **Release Gate Enforcement & Wizard Smoke Test** | `.github/workflows/jules-audit.yml`, `scripts/release.mjs`, `test/wizard-smoke.test.mjs` | Doc-sync gate runs in CI rather than by hand, releases block on a green CI matrix for `HEAD`, per-test deadlines turn a hang into a failure, and the real `init` wizard is driven end to end over a fake TTY. | **v0.38.1** *(Shipped)* |
323
328
  | **Multi-OS CI Matrix & TUI Hardening** | `scripts/run-tests.mjs`, `src/state.mjs`, `src/git.mjs` | Automated 9-job CI matrix across Linux, macOS, and Windows on Node 20/22/24 with raw-mode TUI resilience and native Windows command quoting. | **v0.38.0** *(Shipped)* |
324
329
  | **Base64 Secret Detection & Budget Fix** | `src/security.mjs`, `src/budget.mjs` | Secret scanner decodes base64 before matching structured patterns (K8s secrets), and `budget reset` preserves confirmed provider sessions. | **v0.37.0** *(Shipped)* |
package/bin/agentctl.mjs CHANGED
@@ -40,7 +40,7 @@ export function printHelp() {
40
40
  Usage: agentctl <command> [options]
41
41
 
42
42
  Commands:
43
- dispatch | create Dispatch a single task to an AI agent (--role <name>, --tier fast|complex)
43
+ dispatch | create Dispatch a single task to an AI agent (--role <name>, --tier fast|complex, --check-premise)
44
44
  gate | audit Run CI security and verification gate against current branch
45
45
  queue Run pending task queue (--dag, --concurrency <n>)
46
46
  swarm Run parallel task swarm
@@ -54,12 +54,15 @@ Commands:
54
54
  init Scaffold .agent/ config and run onboarding wizard
55
55
  task create Interactively author and scope a Jules task envelope (--template <name>, --role <name>, --tier fast|complex)
56
56
  task optimize Linter & optimizer for Jules task prompts (--fix, --json, --web)
57
- task template List and generate web development task templates (--list, --json)
57
+ task template List and generate task templates (--list, --json)
58
58
  test-gen Scaffold & run automated TDD Red-to-Green test cycle (--run)
59
59
  mcp init Scaffold IDE integration config (cursor | vscode | claude | all)
60
60
  rollback Restore git state & working tree to atomic pre-flight checkpoint
61
61
  handover Inspect or generate Baton Pass session handover envelopes (list | show | create | prune)
62
62
  resume Resume warm session with human response (--response "<text>")
63
+ plan approve <id> Approve pending plan for a Jules session (:approvePlan)
64
+ session get <id> Retrieve remote session status from provider API
65
+ pr harvest Triage, verify CI, and auto-merge low-risk agent PRs (--auto, --tier r0,r1)
63
66
  escalate Dispatch or manage webhook escalation incidents (--flush, --status, --clear)
64
67
  flaky Manage Wilson-quarantined tests and dispatch healing swarm (status | heal | reset)
65
68
  status Display queue and system status summary
@@ -69,11 +72,13 @@ Commands:
69
72
  harvest Harvest failure traces and record/quarantine resolution rules
70
73
  learning add Record a system learning rule into .agent/knowledge/
71
74
  evidence <action> Manage cryptographic audit evidence (generate | verify | show)
75
+ assert Run declarative zero-dependency verification assertion primitives
72
76
  version Output agentctl version
73
77
 
74
78
  Options:
75
79
  --role, -r Specify specialist agent role (overseer | bolt | sentinel | janitor)
76
80
  --tier Force routing tier when router.enabled (fast | complex) — see .agent/config.yml router:
81
+ --check-premise Verify task goal/oracle passes locally before burning API budget
77
82
  --dag Execute queue tasks via DAG dependency resolution
78
83
  --dry-run, -d Simulate action without making API calls or modifying git
79
84
  --mode, -m Gate evaluation mode (working-tree | committed | staged)
@@ -81,6 +86,7 @@ Options:
81
86
  --source, -s Specify Jules repository source name
82
87
  --branch, -b Specify target starting branch
83
88
  --json, -j Emit machine-readable JSON output
89
+ --json-report <path> Write structured machine-readable JSON diagnostics report
84
90
  --help, -h Show command help
85
91
  `);
86
92
  }
@@ -147,6 +153,8 @@ async function main() {
147
153
  repoless: { type: "boolean" },
148
154
  "auto-pr": { type: "boolean" },
149
155
  "require-plan-approval": { type: "boolean" },
156
+ "check-premise": { type: "boolean" },
157
+ idempotent: { type: "boolean" },
150
158
  "dry-run": { type: "boolean", short: "d" },
151
159
  json: { type: "boolean", short: "j" },
152
160
  },
@@ -177,6 +185,7 @@ async function main() {
177
185
  repoless: values.repoless,
178
186
  autoPr: values["auto-pr"],
179
187
  requirePlanApproval: values["require-plan-approval"],
188
+ checkPremise: values["check-premise"] || values.idempotent,
180
189
  };
181
190
 
182
191
  try {
@@ -187,15 +196,21 @@ async function main() {
187
196
  repoless: values.repoless,
188
197
  source: values.source,
189
198
  branch: values.branch,
199
+ checkPremise: values["check-premise"] || values.idempotent,
190
200
  });
191
201
  if (values.json) {
192
202
  console.log(JSON.stringify({ ok: true, session }, null, 2));
193
203
  } else {
194
- console.log(`\n✅ Task Dispatched Successfully!`);
195
- console.log(` Session ID : ${session.id}`);
196
- console.log(` Session URL : ${session.url || "N/A"}`);
197
- if (session._routeTier) {
198
- console.log(` Router Tier : ${session._routeTier} (${session._routeReason || "n/a"})`);
204
+ if (session.status === "ALREADY_SATISFIED" || session.skipped) {
205
+ console.log(`\n⚡ Task Already Satisfied (skipped dispatch):`);
206
+ console.log(` Reason: ${session.reason || "Verification oracle already passing on base branch."}`);
207
+ } else {
208
+ console.log(`\n✅ Task Dispatched Successfully!`);
209
+ console.log(` Session ID : ${session.id}`);
210
+ console.log(` Session URL : ${session.url || "N/A"}`);
211
+ if (session._routeTier) {
212
+ console.log(` Router Tier : ${session._routeTier} (${session._routeReason || "n/a"})`);
213
+ }
199
214
  }
200
215
  }
201
216
  process.exit(0);
@@ -224,6 +239,7 @@ async function main() {
224
239
  fix: { type: "boolean" },
225
240
  "allow-protected": { type: "boolean" },
226
241
  json: { type: "boolean", short: "j" },
242
+ "json-report": { type: "string" },
227
243
  "dry-run": { type: "boolean", short: "d" },
228
244
  },
229
245
  allowPositionals: true,
@@ -241,6 +257,7 @@ async function main() {
241
257
  mode: selectedMode,
242
258
  fix: values.fix,
243
259
  allowProtected: values["allow-protected"],
260
+ jsonReport: values["json-report"],
244
261
  });
245
262
 
246
263
  if (values.json) {
@@ -285,6 +302,93 @@ async function main() {
285
302
  break;
286
303
  }
287
304
 
305
+ case "assert": {
306
+ const { runAssertion, parseYaml } = await import("../index.mjs");
307
+ const { values } = parseArgs({
308
+ args: args.slice(1),
309
+ options: {
310
+ dir: { type: "string", short: "d" },
311
+ file: { type: "string", short: "f" },
312
+ targets: { type: "string", short: "t" },
313
+ patterns: { type: "string", short: "p" },
314
+ "patterns-file": { type: "string" },
315
+ "max-bytes": { type: "string" },
316
+ "max-kb": { type: "string" },
317
+ "max-mb": { type: "string" },
318
+ gzip: { type: "boolean" },
319
+ config: { type: "string", short: "c" },
320
+ json: { type: "boolean", short: "j" },
321
+ "json-report": { type: "string" },
322
+ },
323
+ allowPositionals: true,
324
+ });
325
+
326
+ let stageConfig = {};
327
+ if (values.config && existsSync(values.config)) {
328
+ const raw = readFileSync(values.config, "utf-8");
329
+ stageConfig = parseYaml(raw);
330
+ } else {
331
+ let assertType = "dir-size";
332
+ if (values.file) assertType = "file-size";
333
+ else if (values.patterns || values["patterns-file"] || values.targets) assertType = "file-patterns";
334
+ else if (values.dir) assertType = "dir-size";
335
+
336
+ stageConfig = {
337
+ assert: assertType,
338
+ path: values.dir || values.file,
339
+ targets: values.targets ? values.targets.split(",").map((s) => s.trim()) : undefined,
340
+ patterns: values.patterns ? values.patterns.split(",").map((s) => s.trim()) : undefined,
341
+ patternsFile: values["patterns-file"],
342
+ maxBytes: values["max-bytes"] ? Number(values["max-bytes"]) : undefined,
343
+ maxKb: values["max-kb"] ? Number(values["max-kb"]) : undefined,
344
+ maxMb: values["max-mb"] ? Number(values["max-mb"]) : undefined,
345
+ gzip: values.gzip,
346
+ };
347
+ }
348
+
349
+ const result = runAssertion(stageConfig, root);
350
+ if (values["json-report"]) {
351
+ const { exportJsonReport, generateEvidenceManifest } = await import("../src/evidence.mjs");
352
+ const dummyManifest = generateEvidenceManifest(root, {
353
+ taskId: "CLI-ASSERT",
354
+ title: "Ad-hoc Assertion",
355
+ executionRecords: [
356
+ {
357
+ id: result.assertionType,
358
+ kind: "assert",
359
+ assert: result.assertionType,
360
+ exitCode: result.status,
361
+ durationMs: result.metrics?.durationMs || 0,
362
+ diagnostics: result.diagnostics,
363
+ metrics: result.metrics,
364
+ },
365
+ ],
366
+ diagnostics: result.diagnostics,
367
+ metrics: result.metrics,
368
+ ok: result.ok,
369
+ });
370
+ exportJsonReport(dummyManifest, values["json-report"]);
371
+ }
372
+
373
+ if (values.json) {
374
+ console.log(JSON.stringify(result, null, 2));
375
+ } else {
376
+ if (result.ok) {
377
+ console.log(`\n✅ Assertion [${result.assertionType}] PASSED (${result.metrics?.durationMs || 0}ms)`);
378
+ if (result.metrics?.measuredBytes !== undefined) {
379
+ console.log(` Measured : ${result.metrics.measuredBytes} bytes${result.metrics.gzip ? " (gzipped)" : ""}`);
380
+ }
381
+ } else {
382
+ console.error(`\n❌ Assertion [${result.assertionType}] FAILED (Exit 1)`);
383
+ for (const d of result.diagnostics) {
384
+ console.error(` - ${d}`);
385
+ }
386
+ }
387
+ }
388
+ process.exit(result.status);
389
+ break;
390
+ }
391
+
288
392
  case "queue": {
289
393
  const { values } = parseArgs({
290
394
  args: args.slice(1),
@@ -643,7 +747,7 @@ async function main() {
643
747
  if (values.json) {
644
748
  console.log(JSON.stringify({ ok: true, templates }, null, 2));
645
749
  } else {
646
- console.log(`\n🌐 Available Web Development Task Templates`);
750
+ console.log(`\n📋 Available Task Templates & Envelopes`);
647
751
  console.log(`--------------------------------------------------`);
648
752
  templates.forEach((t) => {
649
753
  console.log(` • ${t.id.padEnd(16)} [${t.category}]`);
@@ -977,6 +1081,160 @@ async function main() {
977
1081
  break;
978
1082
  }
979
1083
 
1084
+ case "plan": {
1085
+ const subAction = args[1];
1086
+ if (subAction === "approve") {
1087
+ const sessionId = args[2];
1088
+ const { values, positionals } = parseArgs({
1089
+ args: args.slice(2),
1090
+ options: {
1091
+ "dry-run": { type: "boolean", short: "d" },
1092
+ json: { type: "boolean", short: "j" },
1093
+ },
1094
+ allowPositionals: true,
1095
+ });
1096
+ const targetSessionId = sessionId && !sessionId.startsWith("-") ? sessionId : positionals?.[0];
1097
+ if (!targetSessionId) {
1098
+ console.error("Error: Session ID is required for agentctl plan approve <sessionId>.");
1099
+ process.exit(1);
1100
+ }
1101
+ const { createProvider } = await import("../src/provider.mjs");
1102
+ const provider = createProvider(config.provider || "jules", config);
1103
+ try {
1104
+ const res = await provider.approvePlan(targetSessionId, { root, dryRun: values["dry-run"] });
1105
+ if (values.json) {
1106
+ console.log(JSON.stringify(res, null, 2));
1107
+ } else {
1108
+ console.log(`\n✅ Plan Approved Successfully!`);
1109
+ console.log(` Session ID : ${res.id}`);
1110
+ console.log(` Status : ${res.status}\n`);
1111
+ }
1112
+ process.exit(0);
1113
+ } catch (err) {
1114
+ console.error(`❌ Plan Approval Failed: ${err.message}`);
1115
+ process.exit(1);
1116
+ }
1117
+ }
1118
+ console.error(`Error: Unknown plan subcommand '${subAction}'. Use approve.`);
1119
+ process.exit(1);
1120
+ break;
1121
+ }
1122
+
1123
+ case "approve": {
1124
+ const sessionId = args[1];
1125
+ const { values, positionals } = parseArgs({
1126
+ args: args.slice(1),
1127
+ options: {
1128
+ "dry-run": { type: "boolean", short: "d" },
1129
+ json: { type: "boolean", short: "j" },
1130
+ },
1131
+ allowPositionals: true,
1132
+ });
1133
+ const targetSessionId = sessionId && !sessionId.startsWith("-") ? sessionId : positionals?.[0];
1134
+ if (!targetSessionId) {
1135
+ console.error("Error: Session ID is required for agentctl approve <sessionId>.");
1136
+ process.exit(1);
1137
+ }
1138
+ const { createProvider } = await import("../src/provider.mjs");
1139
+ const provider = createProvider(config.provider || "jules", config);
1140
+ try {
1141
+ const res = await provider.approvePlan(targetSessionId, { root, dryRun: values["dry-run"] });
1142
+ if (values.json) {
1143
+ console.log(JSON.stringify(res, null, 2));
1144
+ } else {
1145
+ console.log(`\n✅ Plan Approved Successfully!`);
1146
+ console.log(` Session ID : ${res.id}`);
1147
+ console.log(` Status : ${res.status}\n`);
1148
+ }
1149
+ process.exit(0);
1150
+ } catch (err) {
1151
+ console.error(`❌ Plan Approval Failed: ${err.message}`);
1152
+ process.exit(1);
1153
+ }
1154
+ break;
1155
+ }
1156
+
1157
+ case "session": {
1158
+ const subAction = args[1];
1159
+ if (subAction === "get" || subAction === "status") {
1160
+ const sessionId = args[2];
1161
+ const { values, positionals } = parseArgs({
1162
+ args: args.slice(2),
1163
+ options: {
1164
+ "dry-run": { type: "boolean", short: "d" },
1165
+ json: { type: "boolean", short: "j" },
1166
+ },
1167
+ allowPositionals: true,
1168
+ });
1169
+ const targetSessionId = sessionId && !sessionId.startsWith("-") ? sessionId : positionals?.[0];
1170
+ if (!targetSessionId) {
1171
+ console.error("Error: Session ID is required for agentctl session get <sessionId>.");
1172
+ process.exit(1);
1173
+ }
1174
+ const { createProvider } = await import("../src/provider.mjs");
1175
+ const provider = createProvider(config.provider || "jules", config);
1176
+ try {
1177
+ const res = await provider.getSession(targetSessionId, { root, dryRun: values["dry-run"] });
1178
+ if (values.json) {
1179
+ console.log(JSON.stringify(res, null, 2));
1180
+ } else {
1181
+ console.log(`\n📋 Remote Session Status:`);
1182
+ console.log(` Session ID : ${res.id}`);
1183
+ console.log(` Status : ${res.status}\n`);
1184
+ }
1185
+ process.exit(0);
1186
+ } catch (err) {
1187
+ console.error(`❌ Session Retrieval Failed: ${err.message}`);
1188
+ process.exit(1);
1189
+ }
1190
+ }
1191
+ console.error(`Error: Unknown session subcommand '${subAction}'. Use get.`);
1192
+ process.exit(1);
1193
+ break;
1194
+ }
1195
+
1196
+ case "pr": {
1197
+ const subAction = args[1];
1198
+ if (subAction === "harvest") {
1199
+ const { harvestPullRequests, formatHarvestTable } = await import("../src/ops/pr-harvest.mjs");
1200
+ const { values } = parseArgs({
1201
+ args: args.slice(2),
1202
+ options: {
1203
+ tier: { type: "string" },
1204
+ limit: { type: "string" },
1205
+ auto: { type: "boolean" },
1206
+ merge: { type: "boolean" },
1207
+ "dry-run": { type: "boolean", short: "d" },
1208
+ json: { type: "boolean", short: "j" },
1209
+ },
1210
+ allowPositionals: true,
1211
+ });
1212
+
1213
+ const limit = values.limit ? parseInt(values.limit, 10) : 50;
1214
+ try {
1215
+ const res = await harvestPullRequests(root, {
1216
+ tier: values.tier,
1217
+ limit,
1218
+ auto: values.auto || values.merge,
1219
+ dryRun: values["dry-run"],
1220
+ });
1221
+
1222
+ if (values.json) {
1223
+ console.log(JSON.stringify(res, null, 2));
1224
+ } else {
1225
+ console.log(formatHarvestTable(res));
1226
+ }
1227
+ process.exit(0);
1228
+ } catch (err) {
1229
+ console.error(`❌ PR Harvest Failed: ${err.message}`);
1230
+ process.exit(1);
1231
+ }
1232
+ }
1233
+ console.error(`Error: Unknown PR subcommand '${subAction}'. Use harvest.`);
1234
+ process.exit(1);
1235
+ break;
1236
+ }
1237
+
980
1238
  case "escalate": {
981
1239
  const {
982
1240
  dispatchEscalation,
package/index.mjs CHANGED
@@ -149,8 +149,20 @@ export {
149
149
  verifyEvidenceManifest,
150
150
  generateEvidenceMarkdown,
151
151
  computeEvidenceHash,
152
+ exportJsonReport,
152
153
  } from "./src/evidence.mjs";
153
154
 
155
+ // Declarative Assertion Primitives
156
+ export {
157
+ assertDirSize,
158
+ assertFileSize,
159
+ assertFilePatterns,
160
+ assertFileExists,
161
+ runAssertion,
162
+ formatBytes,
163
+ resolveBytesLimit,
164
+ } from "./src/assertions.mjs";
165
+
154
166
  export {
155
167
  resolveDailyLimit,
156
168
  budgetStatus,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jules-orchestrator-kit",
3
- "version": "0.38.1",
3
+ "version": "0.39.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",